diff --git a/gtk2_ardour/automation_controller.cc b/gtk2_ardour/automation_controller.cc index f63f2ed70c..aa23cb2601 100644 --- a/gtk2_ardour/automation_controller.cc +++ b/gtk2_ardour/automation_controller.cc @@ -19,12 +19,16 @@ */ #include + #include "pbd/error.h" + #include "ardour/automation_list.h" #include "ardour/automation_control.h" #include "ardour/event_type_map.h" #include "ardour/automatable.h" #include "ardour/panner.h" +#include "ardour/session.h" + #include "ardour_ui.h" #include "utils.h" #include "automation_controller.h" @@ -121,13 +125,24 @@ AutomationController::value_adjusted() void AutomationController::start_touch() { - _controllable->start_touch(); + _controllable->start_touch (_controllable->session().transport_frame()); } void -AutomationController::end_touch() +AutomationController::end_touch () { - _controllable->stop_touch(); + if (_controllable->automation_state() == Touch) { + + bool mark = false; + double when = 0; + + if (_controllable->session().transport_rolling()) { + mark = true; + when = _controllable->session().transport_frame(); + } + + _controllable->stop_touch (mark, when); + } } void diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index b8a6ad2df9..9ae59f63e6 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -593,14 +593,14 @@ GainMeterBase::meter_point_clicked () gint GainMeterBase::start_gain_touch (GdkEventButton*) { - _amp->gain_control()->start_touch (); + _amp->gain_control()->start_touch (_amp->session().transport_frame()); return FALSE; } gint GainMeterBase::end_gain_touch (GdkEventButton*) { - _amp->gain_control()->stop_touch (); + _amp->gain_control()->stop_touch (false, _amp->session().transport_frame()); return FALSE; } diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index 40f8e16ef8..5e14ecf034 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -45,6 +45,7 @@ #ifdef HAVE_SLV2 #include "ardour/lv2_plugin.h" #endif +#include "ardour/session.h" #include @@ -603,13 +604,13 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptrcontrol->start_touch (); + cui->control->start_touch (cui->control->session().transport_frame()); } void GenericPluginUI::stop_touch (GenericPluginUI::ControlUI* cui) { - cui->control->stop_touch (); + cui->control->stop_touch (false, cui->control->session().transport_frame()); } void diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 69387ad3a2..263a8ec518 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -405,8 +405,10 @@ PannerUI::setup_pan () boost::shared_ptr ac = _panner->pan_control (asz); if (asz) { - bc->StartGesture.connect (sigc::mem_fun (*ac, &AutomationControl::start_touch)); - bc->StopGesture.connect (sigc::mem_fun (*ac, &AutomationControl::stop_touch)); + bc->StartGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch), + boost::weak_ptr (ac))); + bc->StopGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch), + boost::weak_ptr(ac))); } char buf[64]; @@ -459,6 +461,26 @@ PannerUI::setup_pan () } } +void +PannerUI::start_touch (boost::weak_ptr wac) +{ + boost::shared_ptr ac = wac.lock(); + if (!ac) { + return; + } + ac->start_touch (ac->session().transport_frame()); +} + +void +PannerUI::stop_touch (boost::weak_ptr wac) +{ + boost::shared_ptr ac = wac.lock(); + if (!ac) { + return; + } + ac->stop_touch (false, ac->session().transport_frame()); +} + bool PannerUI::pan_button_event (GdkEventButton* ev, uint32_t which) { diff --git a/gtk2_ardour/panner_ui.h b/gtk2_ardour/panner_ui.h index 4ed8767fb1..a1558981f6 100644 --- a/gtk2_ardour/panner_ui.h +++ b/gtk2_ardour/panner_ui.h @@ -45,7 +45,9 @@ namespace ARDOUR { class Session; class Panner; class Delivery; + class AutomationControl; } + namespace Gtkmm2ext { class FastMeter; } @@ -167,6 +169,9 @@ class PannerUI : public Gtk::HBox, public ARDOUR::SessionHandlePtr std::string astyle_string (ARDOUR::AutoStyle); std::string short_astyle_string (ARDOUR::AutoStyle); std::string _astyle_string (ARDOUR::AutoStyle, bool); + + void start_touch (boost::weak_ptr); + void stop_touch (boost::weak_ptr); }; #endif /* __ardour_gtk_panner_ui_h__ */ diff --git a/libs/ardour/amp.cc b/libs/ardour/amp.cc index f2448c06aa..6002a2549d 100644 --- a/libs/ardour/amp.cc +++ b/libs/ardour/amp.cc @@ -70,7 +70,7 @@ Amp::configure_io (ChanCount in, ChanCount out) } void -Amp::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t nframes, bool) +Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t nframes, bool) { if (!_active && !_pending_active) { return; diff --git a/libs/ardour/ardour/amp.h b/libs/ardour/ardour/amp.h index 52aceaf85f..011fef13c0 100644 --- a/libs/ardour/ardour/amp.h +++ b/libs/ardour/ardour/amp.h @@ -43,7 +43,7 @@ public: bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool configure_io (ChanCount in, ChanCount out); - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); bool apply_gain() const { return _apply_gain; } void apply_gain(bool yn) { _apply_gain = yn; } diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index e0fe38e67e..469025c693 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -61,7 +61,7 @@ public: void clear_controls (); virtual void automation_snapshot(nframes_t now, bool force); - virtual void transport_stopped (sframes_t now); + virtual void transport_stopped (framepos_t now); virtual std::string describe_parameter(Evoral::Parameter param); diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h index 2d22b9e661..006e74346f 100644 --- a/libs/ardour/ardour/automation_control.h +++ b/libs/ardour/ardour/automation_control.h @@ -64,14 +64,14 @@ public: return ((ARDOUR::AutomationList*)_list.get())->set_automation_state(as); } - inline void start_touch() { + inline void start_touch(double when) { set_touching (true); - return ((ARDOUR::AutomationList*)_list.get())->start_touch(); + return ((ARDOUR::AutomationList*)_list.get())->start_touch(when); } - inline void stop_touch() { + inline void stop_touch(bool mark, double when) { set_touching (false); - return ((ARDOUR::AutomationList*)_list.get())->stop_touch(); + return ((ARDOUR::AutomationList*)_list.get())->stop_touch(mark, when); } /** Set the value and do the right thing based on automation state @@ -86,6 +86,8 @@ public: double lower() const { return parameter().min(); } double upper() const { return parameter().max(); } + const ARDOUR::Session& session() const { return _session; } + protected: ARDOUR::Session& _session; }; diff --git a/libs/ardour/ardour/automation_list.h b/libs/ardour/ardour/automation_list.h index acb071cca7..9a5420e74b 100644 --- a/libs/ardour/ardour/automation_list.h +++ b/libs/ardour/ardour/automation_list.h @@ -61,19 +61,21 @@ class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlL PBD::Signal0 automation_style_changed; bool automation_playback() const { - return (_state & Play) || ((_state & Touch) && !_touching); + return (_state & Play) || ((_state & Touch) && !touching()); } bool automation_write () const { - return (_state & Write) || ((_state & Touch) && _touching); - } + return ((_state & Write) || ((_state & Touch) && touching())); + } PBD::Signal0 StateChanged; static PBD::Signal1 AutomationListCreated; - void start_touch (); - void stop_touch (); - bool touching() const { return _touching; } + void start_touch (double when); + void stop_touch (bool mark, double when); + bool touching() const { return g_atomic_int_get (&_touching); } + bool writing() const { return _state == Write; } + bool touch_enabled() const { return _state == Touch; } XMLNode& get_state (); int set_state (const XMLNode &, int version); @@ -86,9 +88,9 @@ class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlL void maybe_signal_changed (); - AutoState _state; - AutoStyle _style; - bool _touching; + AutoState _state; + AutoStyle _style; + gint _touching; }; } // namespace diff --git a/libs/ardour/ardour/delivery.h b/libs/ardour/ardour/delivery.h index ec808a9820..f7cbc29af7 100644 --- a/libs/ardour/ardour/delivery.h +++ b/libs/ardour/ardour/delivery.h @@ -71,10 +71,7 @@ public: /* supplemental method used with MIDI */ void flush_buffers (nframes_t nframes, nframes64_t time); - void transport_stopped (); - void no_outs_cuz_we_no_monitor(bool); - void cycle_start (nframes_t); void increment_output_offset (nframes_t); void transport_stopped (sframes_t frame); @@ -100,8 +97,8 @@ public: void allow_pan_reset (); uint32_t pans_required() const { return _configured_input.n_audio(); } - void start_pan_touch (uint32_t which); - void end_pan_touch (uint32_t which); + void start_pan_touch (uint32_t which, double when); + void end_pan_touch (uint32_t which, bool mark, double when); protected: Role _role; diff --git a/libs/ardour/ardour/internal_return.h b/libs/ardour/ardour/internal_return.h index 2b8e618337..75de954752 100644 --- a/libs/ardour/ardour/internal_return.h +++ b/libs/ardour/ardour/internal_return.h @@ -38,7 +38,7 @@ class InternalReturn : public Return XMLNode& get_state(void); int set_state(const XMLNode&, int version); - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); bool configure_io (ChanCount in, ChanCount out); bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; int set_block_size (nframes_t); diff --git a/libs/ardour/ardour/internal_send.h b/libs/ardour/ardour/internal_send.h index 0764982a93..d2a769982c 100644 --- a/libs/ardour/ardour/internal_send.h +++ b/libs/ardour/ardour/internal_send.h @@ -39,7 +39,7 @@ class InternalSend : public Send XMLNode& get_state(void); int set_state(const XMLNode& node, int version); - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); bool feeds (boost::shared_ptr other) const; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool configure_io (ChanCount in, ChanCount out); diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h index 80adcd4156..dad86d5185 100644 --- a/libs/ardour/ardour/meter.h +++ b/libs/ardour/ardour/meter.h @@ -68,7 +68,7 @@ public: void reflect_inputs (const ChanCount& in); /** Compute peaks */ - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); ChanCount input_streams () const { return current_meters; } ChanCount output_streams () const { return current_meters; } diff --git a/libs/ardour/ardour/monitor_processor.h b/libs/ardour/ardour/monitor_processor.h index e453551b0b..0f23d7029f 100644 --- a/libs/ardour/ardour/monitor_processor.h +++ b/libs/ardour/ardour/monitor_processor.h @@ -110,7 +110,7 @@ class MonitorProcessor : public Processor bool display_to_user() const; - void run (BufferSet& /*bufs*/, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t /*nframes*/, bool /*result_required*/); + void run (BufferSet& /*bufs*/, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t /*nframes*/, bool /*result_required*/); XMLNode& state (bool full); int set_state (const XMLNode&, int /* version */); diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index 62512f6181..087471032d 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -228,7 +228,7 @@ public: bool can_support_io_configuration (const ChanCount& /*in*/, ChanCount& /*out*/) const { return true; }; /// The fundamental Panner function - void run (BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes); + void run (BufferSet& src, BufferSet& dest, framepos_t start_frame, framepos_t end_frames, nframes_t nframes); bool bypassed() const { return _bypassed; } void set_bypassed (bool yn); diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index e4487eb6c0..1fcce61f39 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -52,7 +52,7 @@ class PluginInsert : public Processor XMLNode& get_state(void); int set_state(const XMLNode&, int version); - void run (BufferSet& in, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& in, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); void silence (nframes_t nframes); void activate (); diff --git a/libs/ardour/ardour/port_insert.h b/libs/ardour/ardour/port_insert.h index d30edc7162..f4e20a8045 100644 --- a/libs/ardour/ardour/port_insert.h +++ b/libs/ardour/ardour/port_insert.h @@ -50,7 +50,7 @@ class PortInsert : public IOProcessor XMLNode& get_state(void); int set_state (const XMLNode&, int version); - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); nframes_t signal_latency() const; diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index 1e65bc58bd..55e0cfb2d6 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -63,15 +63,13 @@ class Processor : public SessionObject, public Automatable, public Latent virtual nframes_t signal_latency() const { return 0; } - virtual void transport_stopped (sframes_t /*frame*/) {} - virtual int set_block_size (nframes_t /*nframes*/) { return 0; } virtual bool requires_fixed_sized_buffers() const { return false; } /** @param result_required true if, on return from this method, bufs is required to contain valid data; * if false, the method need not bother writing to bufs if it doesn't want to. */ - virtual void run (BufferSet& /*bufs*/, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t /*nframes*/, bool result_required) {} + virtual void run (BufferSet& /*bufs*/, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t /*nframes*/, bool result_required) {} virtual void silence (nframes_t /*nframes*/) {} virtual void activate () { _pending_active = true; ActiveChanged(); } diff --git a/libs/ardour/ardour/return.h b/libs/ardour/ardour/return.h index 63915e5d78..2dcb6eb270 100644 --- a/libs/ardour/ardour/return.h +++ b/libs/ardour/ardour/return.h @@ -42,7 +42,7 @@ public: uint32_t bit_slot() const { return _bitslot; } - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); boost::shared_ptr amp() const { return _amp; } boost::shared_ptr meter() const { return _meter; } diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h index a060363a23..af806b3c1f 100644 --- a/libs/ardour/ardour/send.h +++ b/libs/ardour/ardour/send.h @@ -55,7 +55,7 @@ class Send : public Delivery uint32_t pans_required() const { return _configured_input.n_audio(); } - void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool); + void run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool); bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool configure_io (ChanCount in, ChanCount out); diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 5ae4e96b4e..68c42ba7b5 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -27,6 +27,7 @@ #include "pbd/error.h" #include "pbd/enumwriter.h" +#include "pbd/stacktrace.h" #include "midi++/names.h" @@ -393,7 +394,7 @@ Automatable::automation_snapshot (nframes_t now, bool force) for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) { boost::shared_ptr c = boost::dynamic_pointer_cast(i->second); - if (c->automation_write()) { + if (_a_session.transport_rolling() && c->automation_write()) { c->list()->rt_add (now, i->second->user_double()); } } @@ -403,20 +404,28 @@ Automatable::automation_snapshot (nframes_t now, bool force) } void -Automatable::transport_stopped (sframes_t now) +Automatable::transport_stopped (framepos_t now) { for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) { boost::shared_ptr c = boost::dynamic_pointer_cast(li->second); - boost::shared_ptr l + if (c) { + boost::shared_ptr l = boost::dynamic_pointer_cast(c->list()); - - c->list()->reposition_for_rt_add (now); - - if (c->automation_state() != Off) { - c->set_value(c->list()->eval(now)); - } + + if (l) { + l->write_pass_finished (now); + + if (l->automation_playback()) { + c->set_value(c->list()->eval(now)); + } + + if (l->automation_state() == Write) { + l->set_automation_state (Touch); + } + } + } } } diff --git a/libs/ardour/automation_list.cc b/libs/ardour/automation_list.cc index 2270b2eff7..53fdb233c6 100644 --- a/libs/ardour/automation_list.cc +++ b/libs/ardour/automation_list.cc @@ -53,7 +53,7 @@ AutomationList::AutomationList (Evoral::Parameter id) { _state = Off; _style = Absolute; - _touching = false; + g_atomic_int_set (&_touching, 0); create_curve_if_necessary(); @@ -67,7 +67,7 @@ AutomationList::AutomationList (const AutomationList& other) { _style = other._style; _state = other._state; - _touching = other._touching; + g_atomic_int_set (&_touching, other.touching()); create_curve_if_necessary(); @@ -80,7 +80,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl { _style = other._style; _state = other._state; - _touching = other._touching; + g_atomic_int_set (&_touching, other.touching()); create_curve_if_necessary(); @@ -94,7 +94,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl AutomationList::AutomationList (const XMLNode& node, Evoral::Parameter id) : ControlList(id) { - _touching = false; + g_atomic_int_set (&_touching, 0); _state = Off; _style = Absolute; @@ -180,6 +180,12 @@ AutomationList::set_automation_state (AutoState s) { if (s != _state) { _state = s; + + if (_state == Write) { + Glib::Mutex::Lock lm (ControlList::_lock); + nascent.push_back (new NascentInfo (false)); + } + automation_state_changed (s); /* EMIT SIGNAL */ } } @@ -194,17 +200,37 @@ AutomationList::set_automation_style (AutoStyle s) } void -AutomationList::start_touch () +AutomationList::start_touch (double when) { - _touching = true; - _new_value = true; + if (_state == Touch) { + Glib::Mutex::Lock lm (ControlList::_lock); + nascent.push_back (new NascentInfo (true, when)); + } + + g_atomic_int_set (&_touching, 1); } void -AutomationList::stop_touch () +AutomationList::stop_touch (bool mark, double when) { - _touching = false; - _new_value = false; + g_atomic_int_set (&_touching, 0); + + if (_state == Touch) { + Glib::Mutex::Lock lm (ControlList::_lock); + + if (mark) { + nascent.back()->end_time = when; + + } else { + + /* nascent info created in start touch but never used. just get rid of it. + */ + + NascentInfo* ninfo = nascent.back (); + nascent.erase (nascent.begin()); + delete ninfo; + } + } } void @@ -247,7 +273,14 @@ AutomationList::state (bool full) root->add_property ("interpolation-style", enum_2_string (_interpolation)); if (full) { - root->add_property ("state", auto_state_to_string (_state)); + /* never serialize state with Write enabled - too dangerous + for the user's data + */ + if (_state != Write) { + root->add_property ("state", auto_state_to_string (_state)); + } else { + root->add_property ("state", auto_state_to_string (Off)); + } } else { /* never save anything but Off for automation state to a template */ root->add_property ("state", auto_state_to_string (Off)); @@ -327,7 +360,6 @@ AutomationList::deserialize_events (const XMLNode& node) error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg; } else { mark_dirty (); - reposition_for_rt_add (0); maybe_signal_changed (); } @@ -426,6 +458,9 @@ AutomationList::set_state (const XMLNode& node, int version) if ((prop = node.property (X_("state"))) != 0) { _state = string_to_auto_state (prop->value()); + if (_state == Write) { + _state = Off; + } } else { _state = Off; } @@ -462,7 +497,6 @@ AutomationList::set_state (const XMLNode& node, int version) freeze (); clear (); mark_dirty (); - reposition_for_rt_add (0); maybe_signal_changed (); thaw (); } diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index d5c982c0cc..50a87eb000 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -221,7 +221,7 @@ Delivery::configure_io (ChanCount in, ChanCount out) } void -Delivery::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool result_required) +Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool result_required) { assert (_output); @@ -418,27 +418,22 @@ Delivery::reset_panners () void -Delivery::start_pan_touch (uint32_t which) +Delivery::start_pan_touch (uint32_t which, double when) { if (which < _panner->npanners()) { - _panner->pan_control(which)->start_touch(); + _panner->pan_control(which)->start_touch(when); } } void -Delivery::end_pan_touch (uint32_t which) +Delivery::end_pan_touch (uint32_t which, bool mark, double when) { if (which < _panner->npanners()) { - _panner->pan_control(which)->stop_touch(); + _panner->pan_control(which)->stop_touch(mark, when); } } -void -Delivery::transport_stopped (sframes_t frame) -{ - _panner->transport_stopped (frame); -} void Delivery::flush_buffers (nframes_t nframes, nframes64_t time) @@ -453,15 +448,19 @@ Delivery::flush_buffers (nframes_t nframes, nframes64_t time) } void -Delivery::transport_stopped () +Delivery::transport_stopped (framepos_t now) { - /* turn off any notes that are on */ + Processor::transport_stopped (now); - PortSet& ports (_output->ports()); + _panner->transport_stopped (now); - for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) { - (*i).transport_stopped (); - } + if (_output) { + PortSet& ports (_output->ports()); + + for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) { + (*i).transport_stopped (); + } + } } gain_t diff --git a/libs/ardour/internal_return.cc b/libs/ardour/internal_return.cc index e1f39b79a3..db3c68a352 100644 --- a/libs/ardour/internal_return.cc +++ b/libs/ardour/internal_return.cc @@ -37,7 +37,7 @@ InternalReturn::InternalReturn (Session& s) } void -InternalReturn::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t nframes, bool) +InternalReturn::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t nframes, bool) { if (!_active && !_pending_active) { return; diff --git a/libs/ardour/internal_send.cc b/libs/ardour/internal_send.cc index a1425e3059..9c4238b134 100644 --- a/libs/ardour/internal_send.cc +++ b/libs/ardour/internal_send.cc @@ -80,7 +80,7 @@ InternalSend::send_to_going_away () } void -InternalSend::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool) +InternalSend::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool) { if ((!_active && !_pending_active) || !target || !_send_to) { _meter->reset (); diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc index 3c53f56db4..443146cf13 100644 --- a/libs/ardour/meter.cc +++ b/libs/ardour/meter.cc @@ -39,7 +39,7 @@ PBD::Signal0 Metering::Meter; * be set to 0. */ void -PeakMeter::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t nframes, bool) +PeakMeter::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t nframes, bool) { if (!_active && !_pending_active) { return; diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 25418ec968..f79ed520c0 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -396,12 +396,9 @@ MidiTrack::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_fram void MidiTrack::handle_transport_stopped (bool abort, bool did_locate, bool flush_processors) { - - _main_outs->transport_stopped (); Route::handle_transport_stopped (abort, did_locate, flush_processors); } - void MidiTrack::push_midi_input_to_step_edit_ringbuffer (nframes_t nframes) { diff --git a/libs/ardour/monitor_processor.cc b/libs/ardour/monitor_processor.cc index bcdc28a4ae..8ea5e70aab 100644 --- a/libs/ardour/monitor_processor.cc +++ b/libs/ardour/monitor_processor.cc @@ -245,7 +245,7 @@ MonitorProcessor::state (bool full) } void -MonitorProcessor::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t nframes, bool /*result_required*/) +MonitorProcessor::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t nframes, bool /*result_required*/) { uint32_t chn = 0; gain_t target_gain; diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index c400199943..3f6b23672a 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -1489,7 +1489,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes } void -Panner::run (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) +Panner::run (BufferSet& inbufs, BufferSet& outbufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes) { if (outbufs.count().n_audio() == 0) { // Failing to deliver audio we were asked to deliver is a bug diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 73655b24b1..d6dfc014cf 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -367,7 +367,7 @@ PluginInsert::silence (nframes_t nframes) } void -PluginInsert::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*end_frame*/, nframes_t nframes, bool) +PluginInsert::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, nframes_t nframes, bool) { if (_active || _pending_active) { diff --git a/libs/ardour/port_insert.cc b/libs/ardour/port_insert.cc index 087d2577ad..20c6b127d2 100644 --- a/libs/ardour/port_insert.cc +++ b/libs/ardour/port_insert.cc @@ -101,7 +101,7 @@ PortInsert::latency() const } void -PortInsert::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool) +PortInsert::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool) { if (_output->n_ports().n_total() == 0) { return; diff --git a/libs/ardour/return.cc b/libs/ardour/return.cc index 10879d7722..d8c8dd22f8 100644 --- a/libs/ardour/return.cc +++ b/libs/ardour/return.cc @@ -103,7 +103,7 @@ Return::set_state (const XMLNode& node, int version) } void -Return::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool) +Return::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool) { if ((!_active && !_pending_active) || _input->n_ports() == ChanCount::ZERO) { return; diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 0f9e7ba241..290d9209d9 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -2621,7 +2621,7 @@ Route::direct_feeds (boost::shared_ptr other, bool* only_send) void Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors) { - nframes_t now = _session.transport_frame(); + framepos_t now = _session.transport_frame(); { Glib::RWLock::ReaderLock lm (_processor_lock); @@ -2630,6 +2630,8 @@ Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool c automation_snapshot (now, true); } + Automatable::transport_stopped (now); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if (Config->get_plugins_stop_with_transport() && can_flush_processors) { diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index 4624006ca9..9d5d2398c7 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -71,7 +71,7 @@ Send::deactivate () } void -Send::run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool) +Send::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes, bool) { if (_output->n_ports() == ChanCount::ZERO) { _meter->reset (); diff --git a/libs/evoral/evoral/ControlList.hpp b/libs/evoral/evoral/ControlList.hpp index 28b9ba2fcd..9d3ba09ef1 100644 --- a/libs/evoral/evoral/ControlList.hpp +++ b/libs/evoral/evoral/ControlList.hpp @@ -114,10 +114,10 @@ public: bool extend_to (double); void slide (iterator before, double distance); - void reposition_for_rt_add (double when); void rt_add (double when, double value); void add (double when, double value); void fast_simple_add (double when, double value); + void merge_nascent (double when); void reset_range (double start, double end); void erase_range (double start, double end); @@ -130,10 +130,6 @@ public: boost::shared_ptr copy (double, double); void clear (double, double); - boost::shared_ptr cut (iterator, iterator); - boost::shared_ptr copy (iterator, iterator); - void clear (iterator, iterator); - bool paste (ControlList&, double position, float times); void set_yrange (double min, double max) { @@ -236,6 +232,11 @@ public: InterpolationStyle interpolation() const { return _interpolation; } void set_interpolation (InterpolationStyle); + virtual bool touching() const { return false; } + virtual bool writing() const { return false; } + virtual bool touch_enabled() const { return false; } + void write_pass_finished (double when); + /** Emitted when mark_dirty() is called on this object */ mutable PBD::Signal0 Dirty; /** Emitted when our interpolation style changes */ @@ -257,25 +258,37 @@ protected: void _x_scale (double factor); - mutable LookupCache _lookup_cache; - mutable SearchCache _search_cache; + mutable LookupCache _lookup_cache; + mutable SearchCache _search_cache; - Parameter _parameter; - InterpolationStyle _interpolation; - EventList _events; - mutable Glib::Mutex _lock; - int8_t _frozen; - bool _changed_when_thawed; - bool _new_value; - double _max_xval; - double _min_yval; - double _max_yval; - double _default_value; - bool _sort_pending; - iterator _rt_insertion_point; - double _rt_pos; + Parameter _parameter; + InterpolationStyle _interpolation; + EventList _events; + mutable Glib::Mutex _lock; + int8_t _frozen; + bool _changed_when_thawed; + double _max_xval; + double _min_yval; + double _max_yval; + double _default_value; + bool _sort_pending; Curve* _curve; + + struct NascentInfo { + EventList events; + bool is_touch; + double start_time; + double end_time; + + NascentInfo (bool touching, double start = -1.0) + : is_touch (touching) + , start_time (start) + , end_time (-1.0) + {} + }; + + std::list nascent; }; } // namespace Evoral diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp index 72b032e0cf..b49b294288 100644 --- a/libs/evoral/src/ControlList.cpp +++ b/libs/evoral/src/ControlList.cpp @@ -45,7 +45,6 @@ ControlList::ControlList (const Parameter& id) _max_yval = id.max(); _max_xval = 0; // means "no limit" _default_value = 0; - _rt_insertion_point = _events.end(); _lookup_cache.left = -1; _lookup_cache.range.first = _events.end(); _search_cache.left = -1; @@ -64,7 +63,6 @@ ControlList::ControlList (const ControlList& other) _max_yval = other._max_yval; _max_xval = other._max_xval; _default_value = other._default_value; - _rt_insertion_point = _events.end(); _lookup_cache.range.first = _events.end(); _search_cache.first = _events.end(); _sort_pending = false; @@ -87,7 +85,6 @@ ControlList::ControlList (const ControlList& other, double start, double end) _max_yval = other._max_yval; _max_xval = other._max_xval; _default_value = other._default_value; - _rt_insertion_point = _events.end(); _lookup_cache.range.first = _events.end(); _search_cache.first = _events.end(); _sort_pending = false; @@ -110,6 +107,13 @@ ControlList::~ControlList() for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) { delete (*x); } + + for (list::iterator n = nascent.begin(); n != nascent.end(); ++n) { + for (EventList::iterator x = (*n)->events.begin(); x != (*n)->events.end(); ++x) { + delete *x; + } + delete (*n); + } delete _curve; } @@ -203,7 +207,8 @@ ControlList::extend_to (double when) return true; } -void ControlList::_x_scale (double factor) +void +ControlList::_x_scale (double factor) { for (iterator i = _events.begin(); i != _events.end(); ++i) { (*i)->when = floor ((*i)->when * factor); @@ -213,90 +218,165 @@ void ControlList::_x_scale (double factor) } void -ControlList::reposition_for_rt_add (double /*when*/) +ControlList::write_pass_finished (double when) { - _rt_insertion_point = _events.end(); + merge_nascent (when); +} + +void +ControlList::merge_nascent (double when) +{ + { + Glib::Mutex::Lock lm (_lock); + + if (nascent.empty()) { + return; + } + + for (list::iterator n = nascent.begin(); n != nascent.end(); ++n) { + + NascentInfo* ninfo = *n; + EventList& nascent_events (ninfo->events); + bool need_adjacent_start_clamp; + bool need_adjacent_end_clamp; + + if (nascent_events.empty()) { + delete ninfo; + continue; + } + + if (ninfo->start_time < 0.0) { + ninfo->start_time = nascent_events.front()->when; + } + + if (ninfo->end_time < 0.0) { + ninfo->end_time = when; + } + + bool preexisting = !_events.empty(); + + if (!preexisting) { + + _events = nascent_events; + + } else if (ninfo->end_time < _events.front()->when) { + + /* all points in nascent are before the first existing point */ + + _events.insert (_events.begin(), nascent_events.begin(), nascent_events.end()); + + } else if (ninfo->start_time > _events.back()->when) { + + /* all points in nascent are after the last existing point */ + + _events.insert (_events.end(), nascent_events.begin(), nascent_events.end()); + + } else { + + /* find the range that overaps with nascent events, + and insert the contents of nascent events. + */ + + iterator i; + iterator range_begin = _events.end(); + iterator range_end = _events.end(); + double end_value = unlocked_eval (ninfo->end_time); + double start_value = unlocked_eval (ninfo->start_time - 1); + + need_adjacent_end_clamp = true; + need_adjacent_start_clamp = true; + + for (i = _events.begin(); i != _events.end(); ++i) { + + if ((*i)->when == ninfo->start_time) { + /* existing point at same time, remove it + and the consider the next point instead. + */ + i = _events.erase (i); + + if (i == _events.end()) { + break; + } + + if (range_begin == _events.end()) { + range_begin = i; + need_adjacent_start_clamp = false; + } else { + need_adjacent_end_clamp = false; + } + + if ((*i)->when > ninfo->end_time) { + range_end = i; + break; + } + + } else if ((*i)->when > ninfo->start_time) { + + if (range_begin == _events.end()) { + range_begin = i; + } + + if ((*i)->when > ninfo->end_time) { + range_end = i; + break; + } + } + } + + assert (range_begin != _events.end()); + + if (range_begin != _events.begin()) { + /* clamp point before */ + if (need_adjacent_start_clamp) { + _events.insert (range_begin, new ControlEvent (ninfo->start_time, start_value)); + } + } + + _events.insert (range_begin, nascent_events.begin(), nascent_events.end()); + + if (range_end != _events.end()) { + /* clamp point after */ + if (need_adjacent_end_clamp) { + _events.insert (range_begin, new ControlEvent (ninfo->end_time, end_value)); + } + } + + _events.erase (range_begin, range_end); + } + + delete ninfo; + } + + nascent.clear (); + + if (writing()) { + nascent.push_back (new NascentInfo (false)); + } + } + + maybe_signal_changed (); } void ControlList::rt_add (double when, double value) { + // this is for automation recording + + if (touch_enabled() && !touching()) { + return; + } + //cerr << "RT: alist " << this << " add " << value << " @ " << when << endl; - { - Glib::Mutex::Lock lm (_lock); + Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK); - iterator where; - ControlEvent cp (when, 0.0); - bool done = false; - - if ((_rt_insertion_point != _events.end()) && ((*_rt_insertion_point)->when < when) ) { - - /* we have a previous insertion point, so we should delete - everything between it and the position where we are going - to insert this point. - */ - - iterator after = _rt_insertion_point; - - if (++after != _events.end()) { - iterator far = after; - - while (far != _events.end()) { - if ((*far)->when > when) { - break; - } - ++far; - } - - if (_new_value) { - where = far; - _rt_insertion_point = where; - - if ((*where)->when == when) { - (*where)->value = value; - done = true; - } - } else { - where = _events.erase (after, far); - } - - } else { - - where = after; - - } - - iterator previous = _rt_insertion_point; - --previous; - - if (_rt_insertion_point != _events.begin() && (*_rt_insertion_point)->value == value && (*previous)->value == value) { - (*_rt_insertion_point)->when = when; - done = true; - - } - - } else { - - where = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); - - if (where != _events.end()) { - if ((*where)->when == when) { - (*where)->value = value; - done = true; - } - } - } - - if (!done) { - _rt_insertion_point = _events.insert (where, new ControlEvent (when, value)); - } - - _new_value = false; - mark_dirty (); - } - - maybe_signal_changed (); + if (lm.locked()) { + assert (!nascent.empty()); + if (!nascent.back()->events.empty()) { + assert (when > nascent.back()->events.back()->when); + } + nascent.back()->events.push_back (new ControlEvent (when, value)); + } } void @@ -336,7 +416,6 @@ ControlList::add (double when, double value) if (insert) { _events.insert (insertion_point, new ControlEvent (when, value)); - reposition_for_rt_add (0); } @@ -352,7 +431,6 @@ ControlList::erase (iterator i) { Glib::Mutex::Lock lm (_lock); _events.erase (i); - reposition_for_rt_add (0); mark_dirty (); } maybe_signal_changed (); @@ -364,7 +442,6 @@ ControlList::erase (iterator start, iterator end) { Glib::Mutex::Lock lm (_lock); _events.erase (start, end); - reposition_for_rt_add (0); mark_dirty (); } maybe_signal_changed (); @@ -411,7 +488,6 @@ ControlList::erase_range (double start, double endt) erased = erase_range_internal (start, endt, _events); if (erased) { - reposition_for_rt_add (0); mark_dirty (); } @@ -662,7 +738,6 @@ ControlList::truncate_end (double last_coordinate) _events.back()->value = last_val; } - reposition_for_rt_add (0); mark_dirty(); } @@ -762,8 +837,6 @@ ControlList::truncate_start (double overall_length) _events.push_front (new ControlEvent (0, first_legal_value)); } - reposition_for_rt_add (0); - mark_dirty(); } @@ -1115,35 +1188,6 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do } } -boost::shared_ptr -ControlList::cut (iterator start, iterator end) -{ - boost::shared_ptr nal = create (_parameter); - - { - Glib::Mutex::Lock lm (_lock); - - for (iterator x = start; x != end; ) { - iterator tmp; - - tmp = x; - ++tmp; - - nal->_events.push_back (new ControlEvent (**x)); - _events.erase (x); - - reposition_for_rt_add (0); - - x = tmp; - } - - mark_dirty (); - } - - maybe_signal_changed (); - - return nal; -} /** @param start Start position in model coordinates. * @param end End position in model coordinates. @@ -1153,15 +1197,16 @@ boost::shared_ptr ControlList::cut_copy_clear (double start, double end, int op) { boost::shared_ptr nal = create (_parameter); - iterator s, e; - bool changed = false; + ControlEvent cp (start, 0.0); { - Glib::Mutex::Lock lm (_lock); + Glib::Mutex::Lock lm (_lock); + + /* first, determine s & e, two iterators that define the range of points + affected by this operation + */ - /* find the first event in our list that is at or before `start' in time */ - ControlEvent cp (start, 0.0); if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) { return nal; } @@ -1170,71 +1215,80 @@ ControlList::cut_copy_clear (double start, double end, int op) cp.when = end; e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator); - if (op != 2 && (*s)->when != start) { - nal->_events.push_back (new ControlEvent (0, unlocked_eval (start))); - } + + /* if "start" isn't the location of an existing point, + evaluate the curve to get a value for the start. Add a point to + both the existing event list, and if its not a "clear" operation, + to the copy ("nal") as well. + + Note that the time positions of the points in each list are different + because we want the copy ("nal") to have a zero time reference. + */ + + + /* before we begin any cut/clear operations, get the value of the curve + at "end". + */ + + double end_value = unlocked_eval (end); + + if ((*s)->when != start) { + + double val = unlocked_eval (start); + + if (op == 0) { // cut + if (start > _events.front()->when) { + _events.insert (s, (new ControlEvent (start, val))); + } + } + + if (op != 2) { // ! clear + nal->_events.push_back (new ControlEvent (0, val)); + } + } for (iterator x = s; x != e; ) { - iterator tmp = x; - ++tmp; - - changed = true; /* adjust new points to be relative to start, which has been set to zero. */ - + if (op != 2) { nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value)); } if (op != 1) { - _events.erase (x); - } + x = _events.erase (x); + } else { + ++x; + } + } + + if (e == _events.end() || (*e)->when != end) { - x = tmp; + /* only add a boundary point if there is a point after "end" + */ + + if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut + _events.insert (e, new ControlEvent (end, end_value)); + } + + if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy + nal->_events.push_back (new ControlEvent (end - start, end_value)); + } } - if (op != 2 && nal->_events.back()->when != end - start) { - nal->_events.push_back (new ControlEvent (end - start, unlocked_eval (end))); - } - - if (changed) { - reposition_for_rt_add (0); - } - - mark_dirty (); + mark_dirty (); } - maybe_signal_changed (); - - return nal; - -} - -boost::shared_ptr -ControlList::copy (iterator start, iterator end) -{ - boost::shared_ptr nal = create (_parameter); - - { - Glib::Mutex::Lock lm (_lock); - - for (iterator x = start; x != end; ) { - iterator tmp; - - tmp = x; - ++tmp; - - nal->_events.push_back (new ControlEvent (**x)); - - x = tmp; - } - } + if (op != 1) { + maybe_signal_changed (); + } return nal; } + boost::shared_ptr ControlList::cut (double start, double end) { @@ -1293,7 +1347,6 @@ ControlList::paste (ControlList& alist, double pos, float /*times*/) } } - reposition_for_rt_add (0); mark_dirty (); } @@ -1342,7 +1395,6 @@ ControlList::move_ranges (const list< RangeMove >& movements) _sort_pending = true; } - reposition_for_rt_add (0); mark_dirty (); }