summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2008-12-16 23:21:01 +0000
committerCarl Hetherington <carl@carlh.net>2008-12-16 23:21:01 +0000
commit2ebb1af2997b8e8f162635b11e8acc5c5d0fe563 (patch)
treea88ebc1e46dbe43cc760626eddd57d0feac81216 /libs
parent43b14aa6098e266f07e1d7dfe4a8a65edda36b0a (diff)
Implement #2425: option for automation to follow region moves.
git-svn-id: svn://localhost/ardour2/branches/3.0@4326 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/configuration_vars.h1
-rw-r--r--libs/ardour/ardour/diskstream.h4
-rw-r--r--libs/ardour/ardour/playlist.h8
-rw-r--r--libs/ardour/ardour/route.h4
-rw-r--r--libs/ardour/diskstream.cc65
-rw-r--r--libs/ardour/playlist.cc67
-rw-r--r--libs/evoral/evoral/ControlList.hpp3
-rw-r--r--libs/evoral/evoral/types.hpp11
-rw-r--r--libs/evoral/src/ControlList.cpp96
9 files changed, 206 insertions, 53 deletions
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index bbf766d877..208fcbb0f0 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -82,6 +82,7 @@ CONFIG_VARIABLE (EditMode, edit_mode, "edit-mode", Slide)
CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", MoveAddHigher)
CONFIG_VARIABLE (bool, link_region_and_track_selection, "link-region-and-track-selection", false)
CONFIG_VARIABLE (std::string, keyboard_layout_name, "keyboard-layout-name", "ansi")
+CONFIG_VARIABLE (bool, automation_follows_regions, "automation-follows-regions", false)
/* monitoring, mute, solo etc */
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 824d864663..955f2ed8e7 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -140,6 +140,8 @@ class Diskstream : public SessionObject
void remove_region_from_last_capture (boost::weak_ptr<Region> wregion);
+ void move_processor_automation (boost::weak_ptr<Processor>, Evoral::RangeMoveList const &);
+
sigc::signal<void> RecordEnableChanged;
sigc::signal<void> SpeedChanged;
sigc::signal<void> ReverseChanged;
@@ -204,6 +206,7 @@ class Diskstream : public SessionObject
virtual void playlist_changed (Change);
virtual void playlist_deleted (boost::weak_ptr<Playlist>);
+ virtual void playlist_ranges_moved (Evoral::RangeMoveList const &);
virtual void transport_stopped (struct tm&, time_t, bool abort) = 0;
virtual void transport_looped (nframes_t transport_frame) = 0;
@@ -299,6 +302,7 @@ class Diskstream : public SessionObject
sigc::connection ports_created_c;
sigc::connection plmod_connection;
sigc::connection plgone_connection;
+ sigc::connection plregion_connection;
Flag _flags;
};
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index b937c412ab..cdde9855b2 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -35,7 +35,9 @@
#include <pbd/undo.h>
#include <pbd/stateful.h>
-#include <pbd/statefuldestructible.h>
+#include <pbd/statefuldestructible.h>
+
+#include <evoral/types.hpp>
#include <ardour/ardour.h>
#include <ardour/session_object.h>
@@ -126,6 +128,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
sigc::signal<void> Modified;
sigc::signal<void> NameChanged;
sigc::signal<void> LengthChanged;
+ sigc::signal<void, Evoral::RangeMoveList const &> RangesMoved;
static string bump_name (string old_name, Session&);
@@ -177,6 +180,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
RegionList regions; /* the current list of regions in the playlist */
std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
+ std::list<sigc::connection> region_state_changed_connections;
DataType _type;
mutable gint block_notifications;
mutable gint ignore_state_changes;
@@ -186,6 +190,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
RegionList pending_bounds;
bool pending_modified;
bool pending_length;
+ Evoral::RangeMoveList pending_range_moves;
bool save_on_thaw;
string last_save_reason;
uint32_t in_set_state;
@@ -227,6 +232,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
void notify_layering_changed ();
void notify_modified ();
void notify_state_changed (Change);
+ void notify_region_moved (boost::shared_ptr<Region>);
void mark_session_dirty();
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 28d15b7090..1d3fc25164 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -142,10 +142,10 @@ class Route : public IO
void flush_processors ();
- template<class T> void foreach_processor (T *obj, void (T::*func)(boost::shared_ptr<Processor>)) {
+ void foreach_processor (sigc::slot<void, boost::weak_ptr<Processor> > method) {
Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
- (obj->*func) (*i);
+ method (boost::weak_ptr<Processor> (*i));
}
}
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index 9665176a67..334e4336af 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -37,6 +37,7 @@
#include <pbd/basename.h>
#include <glibmm/thread.h>
#include <pbd/xml++.h>
+#include <pbd/memento_command.h>
#include <ardour/ardour.h>
#include <ardour/audioengine.h>
@@ -48,6 +49,7 @@
#include <ardour/playlist.h>
#include <ardour/cycle_timer.h>
#include <ardour/region.h>
+#include <ardour/panner.h>
#include "i18n.h"
#include <locale.h>
@@ -312,6 +314,7 @@ Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
plmod_connection.disconnect ();
plgone_connection.disconnect ();
+ plregion_connection.disconnect ();
if (_playlist) {
_playlist->release();
@@ -326,6 +329,7 @@ Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), boost::weak_ptr<Playlist>(_playlist)));
+ plregion_connection = _playlist->RangesMoved.connect (mem_fun (*this, &Diskstream::playlist_ranges_moved));
}
/* don't do this if we've already asked for it *or* if we are setting up
@@ -409,3 +413,64 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
_last_capture_regions.remove (region);
}
+void
+Diskstream::playlist_ranges_moved (Evoral::RangeMoveList const & movements)
+{
+ if (Config->get_automation_follows_regions () == false) {
+ return;
+ }
+
+ /* move gain automation */
+ boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist();
+ XMLNode & before = gain_alist->get_state ();
+ gain_alist->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *gain_alist.get(), &before, &gain_alist->get_state ()
+ )
+ );
+
+ /* move panner automation */
+ Panner & p = _io->panner ();
+ for (uint32_t i = 0; i < p.npanners (); ++i) {
+
+ boost::shared_ptr<AutomationList> pan_alist = p.streampanner(i).pan_control()->alist();
+ XMLNode & before = pan_alist->get_state ();
+ pan_alist->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *pan_alist.get(), &before, &pan_alist->get_state ()
+ )
+ );
+ }
+
+ /* move processor automation */
+ /* XXX: ewww */
+ Route * route = dynamic_cast<Route*> (_io);
+ if (route) {
+ route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements));
+ }
+}
+
+void
+Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, Evoral::RangeMoveList const & movements)
+{
+ boost::shared_ptr<Processor> processor (p.lock ());
+ if (!processor) {
+ return;
+ }
+
+ set<Evoral::Parameter> const a = processor->what_can_be_automated ();
+
+ for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
+ boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
+ XMLNode & before = al->get_state ();
+ al->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *al.get(), &before, &al->get_state ()
+ )
+ );
+ }
+}
+
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index fbe9990933..433e567efa 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -361,6 +361,25 @@ Playlist::notify_region_removed (boost::shared_ptr<Region> r)
}
void
+Playlist::notify_region_moved (boost::shared_ptr<Region> r)
+{
+ Evoral::RangeMove const move (r->last_position (), r->length (), r->position ());
+
+ if (holding_state ()) {
+
+ pending_range_moves.push_back (move);
+
+ } else {
+
+ Evoral::RangeMoveList m;
+ m.push_back (move);
+ RangesMoved (m);
+
+ }
+
+}
+
+void
Playlist::notify_region_added (boost::shared_ptr<Region> r)
{
/* the length change might not be true, but we have to act
@@ -452,9 +471,14 @@ Playlist::flush_notifications ()
check_dependents (*s, false);
}
+ if (!pending_range_moves.empty ()) {
+ RangesMoved (pending_range_moves);
+ }
+
pending_adds.clear ();
pending_removes.clear ();
pending_bounds.clear ();
+ pending_range_moves.clear ();
in_flush = false;
}
@@ -559,8 +583,10 @@ Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t posit
}
}
- region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
- boost::weak_ptr<Region> (region)));
+ region_state_changed_connections.push_back (
+ region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
+ boost::weak_ptr<Region> (region)))
+ );
return true;
}
@@ -1288,20 +1314,22 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
return false;
}
- {
- if (what_changed & BoundsChanged) {
- region_bounds_changed (what_changed, region);
- save = !(_splicing || _nudging);
- }
+ if (what_changed & BoundsChanged) {
+ region_bounds_changed (what_changed, region);
+ save = !(_splicing || _nudging);
+ }
- if ((what_changed & our_interests) &&
- !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
- check_dependents (region, false);
- }
+ if ((what_changed & our_interests) &&
+ !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
+ check_dependents (region, false);
+ }
+
+ if (what_changed & Change (ARDOUR::PositionChanged)) {
+ notify_region_moved (region);
+ }
- if (what_changed & our_interests) {
- save = true;
- }
+ if (what_changed & our_interests) {
+ save = true;
}
return save;
@@ -1320,6 +1348,17 @@ Playlist::clear (bool with_signals)
{
{
RegionLock rl (this);
+
+ for (
+ std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
+ i != region_state_changed_connections.end ();
+ ++i
+ ) {
+
+ i->disconnect ();
+
+ }
+
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
pending_removes.insert (*i);
}
diff --git a/libs/evoral/evoral/ControlList.hpp b/libs/evoral/evoral/ControlList.hpp
index 36799300fe..48050f9e93 100644
--- a/libs/evoral/evoral/ControlList.hpp
+++ b/libs/evoral/evoral/ControlList.hpp
@@ -120,7 +120,7 @@ public:
void erase_range (double start, double end);
void erase (iterator);
void erase (iterator, iterator);
- void move_range (iterator start, iterator end, double, double);
+ void move_ranges (RangeMoveList const &);
void modify (iterator, double, double);
boost::shared_ptr<ControlList> cut (double, double);
@@ -241,6 +241,7 @@ protected:
bool rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
boost::shared_ptr<ControlList> cut_copy_clear (double, double, int op);
+ bool erase_range_internal (double start, double end, EventList &);
virtual void maybe_signal_changed ();
diff --git a/libs/evoral/evoral/types.hpp b/libs/evoral/evoral/types.hpp
index fc1001c7d8..4bca6f1288 100644
--- a/libs/evoral/evoral/types.hpp
+++ b/libs/evoral/evoral/types.hpp
@@ -20,6 +20,7 @@
#define EVORAL_TYPES_HPP
#include <stdint.h>
+#include <list>
namespace Evoral {
@@ -41,6 +42,16 @@ typedef double EventLength;
/** Type of an event (opaque, mapped by application) */
typedef uint32_t EventType;
+/** Type to describe the movement of a time range */
+struct RangeMove {
+ RangeMove (EventTime f, FrameTime l, EventTime t) : from (f), length (l), to (t) {}
+ EventTime from; ///< start of the range
+ FrameTime length; ///< length of the range
+ EventTime to; ///< new start of the range
+};
+
+typedef std::list<RangeMove> RangeMoveList;
+
} // namespace Evoral
#endif // EVORAL_TYPES_HPP
diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp
index e1cea8e191..033e375a8a 100644
--- a/libs/evoral/src/ControlList.cpp
+++ b/libs/evoral/src/ControlList.cpp
@@ -390,16 +390,10 @@ ControlList::erase_range (double start, double endt)
{
Glib::Mutex::Lock lm (_lock);
- ControlEvent cp (start, 0.0f);
- iterator s;
- iterator e;
+ erased = erase_range_internal (start, endt, _events);
- if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) != _events.end()) {
- cp.when = endt;
- e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
- _events.erase (s, e);
+ if (erased) {
reposition_for_rt_add (0);
- erased = true;
mark_dirty ();
}
@@ -410,36 +404,22 @@ ControlList::erase_range (double start, double endt)
}
}
-void
-ControlList::move_range (iterator start, iterator end, double xdelta, double ydelta)
+bool
+ControlList::erase_range_internal (double start, double endt, EventList & events)
{
- /* note: we assume higher level logic is in place to avoid this
- reordering the time-order of control events in the list. ie. all
- points after end are later than (end)->when.
- */
-
- {
- Glib::Mutex::Lock lm (_lock);
-
- while (start != end) {
- (*start)->when += xdelta;
- (*start)->value += ydelta;
- if (isnan ((*start)->value)) {
- abort ();
- }
- ++start;
- }
-
- if (!_frozen) {
- _events.sort (event_time_less_than);
- } else {
- _sort_pending = true;
- }
-
- mark_dirty ();
+ bool erased = false;
+ ControlEvent cp (start, 0.0f);
+ iterator s;
+ iterator e;
+
+ if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
+ cp.when = endt;
+ e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
+ events.erase (s, e);
+ erased = true;
}
- maybe_signal_changed ();
+ return erased;
}
void
@@ -1315,5 +1295,51 @@ ControlList::paste (ControlList& alist, double pos, float times)
return true;
}
+/** Move automation around according to a list of region movements */
+void
+ControlList::move_ranges (RangeMoveList const & movements)
+{
+ {
+ Glib::Mutex::Lock lm (_lock);
+
+ /* a copy of the events list before we started moving stuff around */
+ EventList old_events = _events;
+
+ /* clear the source and destination ranges in the new list */
+ for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
+
+ erase_range_internal (i->from, i->from + i->length, _events);
+ erase_range_internal (i->to, i->to + i->length, _events);
+
+ }
+
+ /* copy the events into the new list */
+ for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
+ iterator j = old_events.begin ();
+ EventTime const limit = i->from + i->length;
+ EventTime const dx = i->to - i->from;
+ while (j != old_events.end () && (*j)->when <= limit) {
+ if ((*j)->when >= i->from) {
+ ControlEvent* ev = new ControlEvent (**j);
+ ev->when += dx;
+ _events.push_back (ev);
+ }
+ ++j;
+ }
+ }
+
+ if (!_frozen) {
+ _events.sort (event_time_less_than);
+ } else {
+ _sort_pending = true;
+ }
+
+ reposition_for_rt_add (0);
+ mark_dirty ();
+ }
+
+ maybe_signal_changed ();
+}
+
} // namespace Evoral