summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-09-21 16:17:02 +0000
committerDavid Robillard <d@drobilla.net>2008-09-21 16:17:02 +0000
commite14187aadd574d46c82d8eb0d151b526b84ddcc7 (patch)
treea80073703c5c3f4a68b4d50aee2c14be7cc1e204 /libs/ardour
parenteec19ca7afde0da57b2a4d9abc6ef847e6924975 (diff)
Display recorded controller data (fix show all/existing automation).
git-svn-id: svn://localhost/ardour2/branches/3.0@3779 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audioregion.h14
-rw-r--r--libs/ardour/ardour/automatable.h43
-rw-r--r--libs/ardour/ardour/automation_control.h7
-rw-r--r--libs/ardour/ardour/io.h4
-rw-r--r--libs/ardour/ardour/midi_model.h18
-rw-r--r--libs/ardour/ardour/midi_region.h28
-rw-r--r--libs/ardour/ardour/midi_track.h6
-rw-r--r--libs/ardour/ardour/panner.h2
-rw-r--r--libs/ardour/ardour/processor.h2
-rw-r--r--libs/ardour/ardour/region.h13
-rw-r--r--libs/ardour/audio_track.cc2
-rw-r--r--libs/ardour/audioregion.cc8
-rw-r--r--libs/ardour/automatable.cc88
-rw-r--r--libs/ardour/automation_control.cc14
-rw-r--r--libs/ardour/io.cc16
-rw-r--r--libs/ardour/jack_slave.cc2
-rw-r--r--libs/ardour/midi_model.cc81
-rw-r--r--libs/ardour/midi_playlist.cc4
-rw-r--r--libs/ardour/midi_stretch.cc2
-rw-r--r--libs/ardour/plugin_insert.cc18
-rw-r--r--libs/ardour/processor.cc3
-rw-r--r--libs/ardour/quantize.cc3
-rw-r--r--libs/ardour/region.cc14
-rw-r--r--libs/ardour/route.cc2
24 files changed, 224 insertions, 170 deletions
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index f8bd8a1794..b8cde44b77 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -123,6 +123,18 @@ class AudioRegion : public Region
void set_default_envelope ();
int separate_by_channel (ARDOUR::Session&, vector<boost::shared_ptr<AudioRegion> >&) const;
+
+ /* automation */
+
+ boost::shared_ptr<Evoral::Control>
+ control(const Evoral::Parameter& id, bool create=false) {
+ return _automatable.data().control(id, create);
+ }
+
+ virtual boost::shared_ptr<const Evoral::Control>
+ control(const Evoral::Parameter& id) const {
+ return _automatable.data().control(id);
+ }
/* export */
@@ -174,6 +186,8 @@ class AudioRegion : public Region
void listen_to_my_curves ();
void listen_to_my_sources ();
+ AutomatableControls _automatable;
+
boost::shared_ptr<AutomationList> _fade_in;
FadeShape _fade_in_shape;
boost::shared_ptr<AutomationList> _fade_out;
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index 99e7891ce8..837bbbc617 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -28,22 +28,28 @@
#include <ardour/automation_control.h>
#include <ardour/parameter.h>
#include <evoral/ControlSet.hpp>
+#include <evoral/Sequence.hpp>
namespace ARDOUR {
class Session;
class AutomationControl;
-class Automatable : public SessionObject, virtual public Evoral::ControlSet
+
+/** Note this class is abstract, actual objects must either be
+ * an AutomatableControls or an AutomatableSequence
+ */
+class Automatable : virtual public Evoral::ControlSet
{
public:
- Automatable(Session&, const std::string& name);
+ Automatable(Session&);
+ Automatable();
virtual ~Automatable() {}
- boost::shared_ptr<Evoral::Control> control_factory(boost::shared_ptr<Evoral::ControlList> list) const;
- boost::shared_ptr<Evoral::ControlList> control_list_factory(const Evoral::Parameter& param) const;
-
+ boost::shared_ptr<Evoral::Control>
+ control_factory(const Evoral::Parameter& id);
+
virtual void add_control(boost::shared_ptr<Evoral::Control>);
virtual void automation_snapshot(nframes_t now, bool force);
@@ -74,8 +80,14 @@ public:
static jack_nframes_t automation_interval() {
return _automation_interval;
}
+
+ typedef Evoral::ControlSet::Controls Controls;
+
+ Evoral::ControlSet& data() { return *this; }
+ const Evoral::ControlSet& data() const { return *this; }
protected:
+ Session& _a_session;
void can_automate(Parameter);
@@ -90,10 +102,29 @@ protected:
std::set<Parameter> _visible_controls;
std::set<Parameter> _can_automate_list;
- nframes_t _last_automation_snapshot;
+ nframes_t _last_automation_snapshot;
static nframes_t _automation_interval;
};
+
+/** Contains notes and controllers */
+class AutomatableSequence : public Automatable, public Evoral::Sequence {
+public:
+ AutomatableSequence(Session& s, size_t size)
+ : Evoral::ControlSet()
+ , Automatable(s)
+ , Evoral::Sequence(size)
+ {}
+};
+
+
+/** Contains only controllers */
+class AutomatableControls : public Automatable {
+public:
+ AutomatableControls(Session& s) : Evoral::ControlSet(), Automatable(s) {}
+};
+
+
} // namespace ARDOUR
#endif /* __ardour_automatable_h__ */
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index 78f4553d87..52fce1096c 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -34,14 +34,15 @@ class Session;
class Automatable;
-/** A PBD:Controllable with associated automation data (AutomationList)
+/** A PBD::Controllable with associated automation data (AutomationList)
*/
class AutomationControl : public PBD::Controllable, public Evoral::Control
{
public:
AutomationControl(ARDOUR::Session&,
- boost::shared_ptr<ARDOUR::AutomationList>,
- std::string name="unnamed controllable");
+ const Parameter& parameter,
+ boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
+ const string& name="");
boost::shared_ptr<AutomationList> alist() const { return boost::dynamic_pointer_cast<AutomationList>(_list); }
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 6cae11a7fa..08c8a1b211 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -69,7 +69,7 @@ class BufferSet;
* varied combinations of types (eg MIDI and audio) possible.
*/
-class IO : public Automatable, public Latent
+class IO : public SessionObject, public AutomatableControls, public Latent
{
public:
static const string state_node_name;
@@ -229,7 +229,7 @@ class IO : public Automatable, public Latent
struct GainControl : public AutomationControl {
GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al)
- : AutomationControl (i._session, al, name)
+ : AutomationControl (i._session, al->parameter(), al, name)
, _io (i)
{}
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index 51bddfde44..a1a0da7296 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -39,7 +39,7 @@ namespace ARDOUR {
class Session;
class MidiSource;
-
+
/** This is a higher level (than MidiBuffer) model of MIDI data, with separate
* representations for notes (instead of just unassociated note on/off events)
* and controller data. Controller data is represented as part of the
@@ -47,7 +47,7 @@ class MidiSource;
* Because of this MIDI controllers and automatable controllers/widgets/etc
* are easily interchangeable.
*/
-class MidiModel : public Automatable, public Evoral::Sequence {
+class MidiModel : public AutomatableSequence {
public:
MidiModel(MidiSource* s, size_t size=0);
@@ -55,13 +55,13 @@ public:
void set_note_mode(NoteMode mode) { set_percussive(mode == Percussive); };
/** Add/Remove notes.
- * Technically all operations can be implemented as one of these.
+ * Technically all note operations can be implemented as one of these, but
+ * a custom command can be more efficient.
*/
- class DeltaCommand : public Command
- {
+ class DeltaCommand : public Command {
public:
DeltaCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
- DeltaCommand (boost::shared_ptr<MidiModel>, const XMLNode& node);
+ DeltaCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node);
const std::string& name() const { return _name; }
@@ -78,8 +78,8 @@ public:
XMLNode &marshal_note(const boost::shared_ptr<Evoral::Note> note);
boost::shared_ptr<Evoral::Note> unmarshal_note(XMLNode *xml_note);
- boost::shared_ptr<MidiModel> _model;
- const std::string _name;
+ boost::shared_ptr<MidiModel> _model;
+ const std::string _name;
typedef std::list< boost::shared_ptr<Evoral::Note> > NoteList;
@@ -88,7 +88,7 @@ public:
};
MidiModel::DeltaCommand* new_delta_command(const std::string name="midi edit");
- void apply_command(Command* cmd);
+ void apply_command(Session& session, Command* cmd);
bool write_to(boost::shared_ptr<MidiSource> source);
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index e0caddd954..2cbed8f99c 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -72,22 +72,28 @@ class MidiRegion : public Region
int set_state (const XMLNode&);
int separate_by_channel (ARDOUR::Session&, vector<MidiRegion*>&) const;
-
- UndoAction get_memento() const;
-
- // Act as a proxy for MidiModel automation stuff (for CC)
- // Yep, this is pretty ugly...
- Controls& controls() { return midi_source()->model()->controls(); }
- const Controls& controls() const { return midi_source()->model()->controls(); }
- boost::shared_ptr<Evoral::Control> control(const Evoral::Parameter& id, bool create=false)
- { return midi_source()->model()->control(id, create); }
+ /* automation */
+
+ boost::shared_ptr<Evoral::Control>
+ control(const Evoral::Parameter& id, bool create=false) {
+ return model()->data().control(id, create);
+ }
- boost::shared_ptr<const Evoral::Control> control(const Evoral::Parameter& id) const
- { return midi_source()->model()->control(id); }
+ virtual boost::shared_ptr<const Evoral::Control>
+ control(const Evoral::Parameter& id) const {
+ return model()->data().control(id);
+ }
+
+ /* export */
int exportme (ARDOUR::Session&, ARDOUR::ExportSpecification&);
+ UndoAction get_memento() const;
+
+ boost::shared_ptr<MidiModel> model() { return midi_source()->model(); }
+ boost::shared_ptr<const MidiModel> model() const { return midi_source()->model(); }
+
private:
friend class RegionFactory;
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 7eda6f904b..02313c7e6e 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -73,9 +73,11 @@ public:
void midi_panic(void);
bool write_immediate_event(size_t size, const uint8_t* buf);
+ /** A control that will send "immediate" events to a MIDI track when twiddled */
struct MidiControl : public AutomationControl {
- MidiControl(MidiTrack* route, boost::shared_ptr<AutomationList> al)
- : AutomationControl (route->session(), al, al->parameter().symbol())
+ MidiControl(MidiTrack* route, const Parameter& param,
+ boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>())
+ : AutomationControl (route->session(), param, al)
, _route (route)
{}
diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h
index 47ef212d58..fb8048e7ef 100644
--- a/libs/ardour/ardour/panner.h
+++ b/libs/ardour/ardour/panner.h
@@ -104,7 +104,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
struct PanControllable : public AutomationControl {
PanControllable (Session& s, std::string name, StreamPanner& p, Parameter param)
- : AutomationControl (s,
+ : AutomationControl (s, param,
boost::shared_ptr<AutomationList>(new AutomationList(param)), name)
, panner (p)
{ assert(param.type() != NullAutomation); }
diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h
index 8c4ac8dfe5..4b236d159e 100644
--- a/libs/ardour/ardour/processor.h
+++ b/libs/ardour/ardour/processor.h
@@ -42,7 +42,7 @@ class Session;
/* A mixer strip element - plugin, send, meter, etc.
*/
-class Processor : public Automatable, public Latent
+class Processor : public SessionObject, public AutomatableControls, public Latent
{
public:
static const string state_node_name;
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index dc81de6374..d3c8341623 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -45,7 +45,10 @@ enum RegionEditState {
EditChangesID = 2
};
-class Region : public Automatable, public boost::enable_shared_from_this<Region>, public Readable
+class Region
+ : public SessionObject
+ , public boost::enable_shared_from_this<Region>
+ , public Readable
{
public:
typedef std::vector<boost::shared_ptr<Source> > SourceList;
@@ -220,6 +223,14 @@ class Region : public Automatable, public boost::enable_shared_from_this<Region>
std::vector<string> master_source_names();
void set_master_sources (const SourceList&);
+ /* automation */
+
+ virtual boost::shared_ptr<Evoral::Control>
+ control(const Evoral::Parameter& id, bool create=false) = 0;
+
+ virtual boost::shared_ptr<const Evoral::Control>
+ control(const Evoral::Parameter& id) const = 0;
+
/* serialization */
XMLNode& get_state ();
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 532abeb123..0418074ef2 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -604,7 +604,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
if (!diskstream->record_enabled() && _session.transport_rolling()) {
- Glib::Mutex::Lock am (_control_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
if (am.locked() && gain_control()->automation_playback()) {
apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 707f10e91a..2b6b87d061 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -77,6 +77,7 @@ AudioRegion::init ()
/* constructor for use by derived types only */
AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string name)
: Region (s, start, length, name, DataType::AUDIO)
+ , _automatable(s)
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -87,6 +88,7 @@ AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string
/** Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length)
: Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0, Region::Flag(Region::DefaultFlags|Region::External))
+ , _automatable(src->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -102,6 +104,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (src, start, length, name, DataType::AUDIO, layer, flags)
+ , _automatable(src->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -117,6 +120,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (many channels) */
AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
+ , _automatable(srcs[0]->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -128,6 +132,7 @@ AudioRegion::AudioRegion (const SourceList& srcs, nframes_t start, nframes_t len
/** Create a new AudioRegion, that is part of an existing one */
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
: Region (other, offset, length, name, layer, flags)
+ , _automatable(other->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -180,6 +185,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
: Region (other)
+ , _automatable(other->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -196,6 +202,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
: Region (src, node)
+ , _automatable(src->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
@@ -217,6 +224,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
: Region (srcs, node)
+ , _automatable(srcs[0]->session())
, _fade_in (new AutomationList(Parameter(FadeInAutomation)))
, _fade_out (new AutomationList(Parameter(FadeOutAutomation)))
, _envelope (new AutomationList(Parameter(EnvelopeAutomation)))
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index 5595ebc2cf..f77975c303 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -37,10 +37,11 @@ using namespace PBD;
nframes_t Automatable::_automation_interval = 0;
-Automatable::Automatable(Session& _session, const string& name)
- : SessionObject(_session, name)
+Automatable::Automatable(Session& session)
+ : _a_session(session)
, _last_automation_snapshot(0)
-{}
+{
+}
int
Automatable::old_set_automation_state (const XMLNode& node)
@@ -50,7 +51,7 @@ Automatable::old_set_automation_state (const XMLNode& node)
if ((prop = node.property ("path")) != 0) {
load_automation (prop->value());
} else {
- warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+ warning << _("Automation node has no path property") << endmsg;
}
if ((prop = node.property ("visible")) != 0) {
@@ -82,19 +83,20 @@ Automatable::load_automation (const string& path)
if (path[0] == '/') { // legacy
fullpath = path;
} else {
- fullpath = _session.automation_dir();
+ fullpath = _a_session.automation_dir();
fullpath += path;
}
ifstream in (fullpath.c_str());
if (!in) {
- warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
+ warning << string_compose(_("cannot open %2 to load automation data (%3)")
+ , fullpath, strerror (errno)) << endmsg;
return 1;
}
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
set<Parameter> tosave;
- _controls.clear ();
+ controls().clear ();
_last_automation_snapshot = 0;
@@ -116,8 +118,8 @@ Automatable::load_automation (const string& path)
return 0;
bad:
- error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
- _controls.clear ();
+ error << string_compose(_("cannot load automation data from %2"), fullpath) << endmsg;
+ controls().clear ();
return -1;
}
@@ -125,17 +127,16 @@ void
Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
{
Parameter param = ac->parameter();
-
+
+ ControlSet::add_control(ac);
_can_automate_list.insert(param);
-
- // Sync everything (derived classes) up to initial values
- auto_state_changed(param);
+ auto_state_changed(param); // sync everything up
}
void
-Automatable::what_has_visible_data (set<Parameter>& s) const
+Automatable::what_has_visible_data(set<Parameter>& s) const
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
set<Parameter>::const_iterator li;
for (li = _visible_controls.begin(); li != _visible_controls.end(); ++li) {
@@ -194,7 +195,7 @@ Automatable::mark_automation_visible (Parameter what, bool yn)
int
Automatable::set_automation_state (const XMLNode& node, Parameter legacy_param)
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
/* Don't clear controls, since some may be special derived Controllable classes */
@@ -215,20 +216,23 @@ Automatable::set_automation_state (const XMLNode& node, Parameter legacy_param)
const XMLProperty* id_prop = (*niter)->property("automation-id");
Parameter param = (id_prop ? Parameter(id_prop->value()) : legacy_param);
+ if (param.type() == NullAutomation) {
+ warning << "Automation has null type" << endl;
+ continue;
+ }
boost::shared_ptr<AutomationList> al (new AutomationList(**niter, param));
if (!id_prop) {
warning << "AutomationList node without automation-id property, "
<< "using default: " << legacy_param.symbol() << endmsg;
- al->set_parameter(legacy_param);
}
boost::shared_ptr<Evoral::Control> existing = control(param);
if (existing)
existing->set_list(al);
else
- add_control(control_factory(al));
+ add_control(control_factory(param));
} else {
error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg;
@@ -243,14 +247,14 @@ Automatable::set_automation_state (const XMLNode& node, Parameter legacy_param)
XMLNode&
Automatable::get_automation_state ()
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
XMLNode* node = new XMLNode (X_("Automation"));
- if (_controls.empty()) {
+ if (controls().empty()) {
return *node;
}
- for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
+ for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
boost::shared_ptr<AutomationList> l
= boost::dynamic_pointer_cast<AutomationList>(li->second->list());
node->add_child_nocopy (l->get_state ());
@@ -262,14 +266,14 @@ Automatable::get_automation_state ()
void
Automatable::set_parameter_automation_state (Parameter param, AutoState s)
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
boost::shared_ptr<Evoral::Control> c = control (param, true);
boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
if (s != l->automation_state()) {
l->set_automation_state (s);
- _session.set_dirty ();
+ _a_session.set_dirty ();
}
}
@@ -279,7 +283,7 @@ Automatable::get_parameter_automation_state (Parameter param, bool lock)
AutoState result = Off;
if (lock)
- _control_lock.lock();
+ control_lock().lock();
boost::shared_ptr<Evoral::Control> c = control(param);
boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
@@ -288,7 +292,7 @@ Automatable::get_parameter_automation_state (Parameter param, bool lock)
result = l->automation_state();
if (lock)
- _control_lock.unlock();
+ control_lock().unlock();
return result;
}
@@ -296,21 +300,21 @@ Automatable::get_parameter_automation_state (Parameter param, bool lock)
void
Automatable::set_parameter_automation_style (Parameter param, AutoStyle s)
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
boost::shared_ptr<Evoral::Control> c = control(param, true);
boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
if (s != l->automation_style()) {
l->set_automation_style (s);
- _session.set_dirty ();
+ _a_session.set_dirty ();
}
}
AutoStyle
Automatable::get_parameter_automation_style (Parameter param)
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
boost::shared_ptr<Evoral::Control> c = control(param);
boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
@@ -328,7 +332,7 @@ Automatable::protect_automation ()
typedef set<Evoral::Parameter> ParameterSet;
ParameterSet automated_params;
- what_has_data (automated_params);
+ what_has_data(automated_params);
for (ParameterSet::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
@@ -353,7 +357,7 @@ Automatable::automation_snapshot (nframes_t now, bool force)
{
if (force || _last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
- for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
+ for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
boost::shared_ptr<AutomationControl> c
= boost::dynamic_pointer_cast<AutomationControl>(i->second);
if (c->automation_write()) {
@@ -368,7 +372,7 @@ Automatable::automation_snapshot (nframes_t now, bool force)
void
Automatable::transport_stopped (nframes_t now)
{
- for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) {
+ for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
boost::shared_ptr<AutomationControl> c
= boost::dynamic_pointer_cast<AutomationControl>(li->second);
@@ -384,20 +388,16 @@ Automatable::transport_stopped (nframes_t now)
}
boost::shared_ptr<Evoral::Control>
-Automatable::control_factory(boost::shared_ptr<Evoral::ControlList> list) const
+Automatable::control_factory(const Evoral::Parameter& param)
{
- boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(list);
- assert(l);
- if (l->parameter().type() >= MidiCCAutomation
- && l->parameter().type() <= MidiChannelAftertouchAutomation) {
- return boost::shared_ptr<Evoral::Control>(new MidiTrack::MidiControl((MidiTrack*)this, l));
+ boost::shared_ptr<AutomationList> list(new AutomationList(param));
+ Evoral::Control* control = NULL;
+ if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelAftertouchAutomation) {
+ control = new MidiTrack::MidiControl((MidiTrack*)this, param);
} else {
- return boost::shared_ptr<Evoral::Control>(new AutomationControl(_session, l));
+ control = new AutomationControl(_a_session, param);
}
+ control->set_list(list);
+ return boost::shared_ptr<Evoral::Control>(control);
}
-boost::shared_ptr<Evoral::ControlList>
-Automatable::control_list_factory(const Evoral::Parameter& param) const
-{
- return boost::shared_ptr<Evoral::ControlList>(new AutomationList(param));
-}
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
index a16306838a..afa14c3f98 100644
--- a/libs/ardour/automation_control.cc
+++ b/libs/ardour/automation_control.cc
@@ -29,9 +29,13 @@ using namespace ARDOUR;
using namespace PBD;
-AutomationControl::AutomationControl(Session& session, boost::shared_ptr<AutomationList> list, string name)
- : Controllable((name == "unnamed controllable") ? list->parameter().symbol() : name)
- , Evoral::Control(list)
+AutomationControl::AutomationControl(
+ ARDOUR::Session& session,
+ const Parameter& parameter,
+ boost::shared_ptr<ARDOUR::AutomationList> list,
+ const string& name)
+ : Controllable((name != "") ? name : parameter.symbol())
+ , Evoral::Control(parameter, list)
, _session(session)
{
}
@@ -42,7 +46,7 @@ AutomationControl::AutomationControl(Session& session, boost::shared_ptr<Automat
float
AutomationControl::get_value() const
{
- bool from_list = ((AutomationList*)_list.get())->automation_playback();
+ bool from_list = _list && ((AutomationList*)_list.get())->automation_playback();
return Control::get_value(from_list, _session.transport_frame());
}
@@ -50,7 +54,7 @@ AutomationControl::get_value() const
void
AutomationControl::set_value(float value)
{
- bool to_list = _session.transport_stopped()
+ bool to_list = _list && _session.transport_stopped()
&& ((AutomationList*)_list.get())->automation_playback();
Control::set_value(value, to_list, _session.transport_frame());
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 69c74f5f03..7db2493c76 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -103,7 +103,8 @@ static double direct_gain_to_control (gain_t gain) {
IO::IO (Session& s, const string& name,
int input_min, int input_max, int output_min, int output_max,
DataType default_type, bool public_ports)
- : Automatable (s, name),
+ : SessionObject(s, name),
+ AutomatableControls (s),
_output_buffers (new BufferSet()),
_active(true),
_default_type (default_type),
@@ -162,8 +163,9 @@ IO::IO (Session& s, const string& name,
}
IO::IO (Session& s, const XMLNode& node, DataType dt)
- : Automatable (s, "unnamed io"),
- _output_buffers (new BufferSet()),
+ : SessionObject(s, "unnamed io"),
+ AutomatableControls (s),
+ _output_buffers (new BufferSet()),
_active(true),
_default_type (dt)
{
@@ -2266,7 +2268,7 @@ IO::meter ()
void
IO::clear_automation ()
{
- Automatable::clear (); // clears gain automation
+ data().clear (); // clears gain automation
_panner->clear_automation ();
}
@@ -2280,7 +2282,7 @@ IO::set_parameter_automation_state (Parameter param, AutoState state)
bool changed = false;
{
- Glib::Mutex::Lock lm (_control_lock);
+ Glib::Mutex::Lock lm (control_lock());
boost::shared_ptr<AutomationList> gain_auto
= boost::dynamic_pointer_cast<AutomationList>(_gain_control->list());
@@ -2302,7 +2304,7 @@ IO::set_parameter_automation_state (Parameter param, AutoState state)
}
} else {
- Automatable::set_parameter_automation_state(param, state);
+ AutomatableControls::set_parameter_automation_state(param, state);
}
}
@@ -2366,7 +2368,7 @@ IO::end_pan_touch (uint32_t which)
void
IO::automation_snapshot (nframes_t now, bool force)
{
- Automatable::automation_snapshot (now, force);
+ AutomatableControls::automation_snapshot (now, force);
if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
_panner->snapshot (now);
diff --git a/libs/ardour/jack_slave.cc b/libs/ardour/jack_slave.cc
index f65be1deea..7865f5253b 100644
--- a/libs/ardour/jack_slave.cc
+++ b/libs/ardour/jack_slave.cc
@@ -87,6 +87,8 @@ JACK_Slave::speed_and_position (float& sp, nframes_t& position)
_starting = true;
// don't adjust speed here, just leave it as it was
break;
+ default:
+ cerr << "WARNING: Unknown JACK transport state: " << state << endl;
}
sp = speed;
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index da0fa364b9..c22820c83c 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -37,11 +37,10 @@ using namespace ARDOUR;
MidiModel::MidiModel(MidiSource *s, size_t size)
- : ControlSet()
- , Automatable(s->session(), "midi model")
- , Sequence(size)
+ : AutomatableSequence(s->session(), size)
, _midi_source(s)
{
+ cerr << "MidiModel \"" << s->name() << "\" constructed: " << this << endl;
}
/** Start a new command.
@@ -62,13 +61,13 @@ MidiModel::DeltaCommand* MidiModel::new_delta_command(const string name)
* The command will constitute one item on the undo stack.
*/
void
-MidiModel::apply_command(Command* cmd)
+MidiModel::apply_command(Session& session, Command* cmd)
{
- _session.begin_reversible_command(cmd->name());
+ session.begin_reversible_command(cmd->name());
(*cmd)();
assert(is_sorted());
- _session.commit_reversible_command(cmd);
- _edited = true;
+ session.commit_reversible_command(cmd);
+ set_edited(true);
}
@@ -110,35 +109,22 @@ MidiModel::DeltaCommand::operator()()
{
// This could be made much faster by using a priority_queue for added and
// removed notes (or sort here), and doing a single iteration over _model
-
- // Need to reset iterator to drop the read lock it holds, or we'll deadlock
- const bool reset_iter = (_model->_read_iter.locked());
- double iter_time = -1.0;
-
- if (reset_iter) {
- if (_model->_read_iter.get_event_pointer().get()) {
- iter_time = _model->_read_iter->time();
- } else {
- cerr << "MidiModel::DeltaCommand::operator(): WARNING: _read_iter points to no event" << endl;
- }
- _model->_read_iter = _model->end(); // drop read lock
- }
-
- assert( ! _model->_read_iter.locked());
-
+
_model->write_lock();
- for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
+ // Store the current seek position so we can restore the read iterator
+ // after modifying the contents of the model
+ const double read_time = _model->read_time();
+
+ for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
_model->add_note_unlocked(*i);
- for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
+ for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
_model->remove_note_unlocked(*i);
_model->write_unlock();
-
- if (reset_iter && iter_time != -1.0) {
- _model->_read_iter = const_iterator(*_model.get(), iter_time);
- }
+ // FIXME: race?
+ _model->read_seek(read_time); // restore read position
_model->ContentsChanged(); /* EMIT SIGNAL */
}
@@ -148,37 +134,22 @@ MidiModel::DeltaCommand::undo()
{
// This could be made much faster by using a priority_queue for added and
// removed notes (or sort here), and doing a single iteration over _model
-
- // Need to reset iterator to drop the read lock it holds, or we'll deadlock
- const bool reset_iter = (_model->_read_iter.locked());
- double iter_time = -1.0;
-
- if (reset_iter) {
- if (_model->_read_iter.get_event_pointer().get()) {
- iter_time = _model->_read_iter->time();
- } else {
- cerr << "MidiModel::DeltaCommand::undo(): WARNING: _read_iter points to no event" << endl;
- }
- _model->_read_iter = _model->end(); // drop read lock
- }
-
- assert( ! _model->_read_iter.locked());
-
+
_model->write_lock();
- for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i = _added_notes.begin(); i
- != _added_notes.end(); ++i)
+ // Store the current seek position so we can restore the read iterator
+ // after modifying the contents of the model
+ const double read_time = _model->read_time();
+
+ for (NoteList::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
_model->remove_note_unlocked(*i);
- for (std::list< boost::shared_ptr<Evoral::Note> >::iterator i =
- _removed_notes.begin(); i != _removed_notes.end(); ++i)
+ for (NoteList::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
_model->add_note_unlocked(*i);
_model->write_unlock();
-
- if (reset_iter && iter_time != -1.0) {
- _model->_read_iter = const_iterator(*_model.get(), iter_time);
- }
+ // FIXME: race?
+ _model->read_seek(read_time); // restore read position
_model->ContentsChanged(); /* EMIT SIGNAL */
}
@@ -300,14 +271,14 @@ bool MidiModel::write_to(boost::shared_ptr<MidiSource> source)
const bool old_percussive = percussive();
set_percussive(false);
- for (const_iterator i = begin(); i != end(); ++i) {
+ for (Evoral::Sequence::const_iterator i = begin(); i != end(); ++i) {
source->append_event_unlocked(Frames, *i);
}
set_percussive(old_percussive);
read_unlock();
- _edited = false;
+ set_edited(false);
return true;
}
diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc
index d258d49524..9ac1d41994 100644
--- a/libs/ardour/midi_playlist.cc
+++ b/libs/ardour/midi_playlist.cc
@@ -279,8 +279,8 @@ MidiPlaylist::contained_automation()
for (RegionList::const_iterator r = regions.begin(); r != regions.end(); ++r) {
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*r);
- for (Automatable::Controls::iterator c = mr->controls().begin();
- c != mr->controls().end(); ++c) {
+ for (Automatable::Controls::iterator c = mr->model()->controls().begin();
+ c != mr->model()->controls().end(); ++c) {
ret.insert(c->first);
}
}
diff --git a/libs/ardour/midi_stretch.cc b/libs/ardour/midi_stretch.cc
index c11963c9d5..975ec6d714 100644
--- a/libs/ardour/midi_stretch.cc
+++ b/libs/ardour/midi_stretch.cc
@@ -87,7 +87,7 @@ MidiStretch::run (boost::shared_ptr<Region> r)
boost::shared_ptr<MidiModel> new_model = new_src->model();
new_model->start_write();
- for (MidiModel::const_iterator i = old_model->begin(); i != old_model->end(); ++i) {
+ for (Evoral::Sequence::const_iterator i = old_model->begin(); i != old_model->end(); ++i) {
const double new_time = i->time() * _request.time_fraction;
// FIXME: double copy
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index b82ba28290..fde0281ed1 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -153,7 +153,7 @@ PluginInsert::auto_state_changed (Parameter which)
return;
boost::shared_ptr<AutomationControl> c
- = boost::dynamic_pointer_cast<AutomationControl>(control (which));
+ = boost::dynamic_pointer_cast<AutomationControl>(data().control (which));
if (c && ((AutomationList*)c->list().get())->automation_state() != Off) {
_plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame()));
@@ -290,7 +290,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
uint32_t n = 0;
- for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li, ++n) {
+ for (Controls::iterator li = data().controls().begin(); li != data().controls().end(); ++li, ++n) {
boost::shared_ptr<AutomationControl> c
= boost::dynamic_pointer_cast<AutomationControl>(li->second);
@@ -368,7 +368,7 @@ PluginInsert::set_parameter (Parameter param, float val)
_plugins[0]->set_parameter (param.id(), val);
- boost::shared_ptr<Evoral::Control> c = control (param);
+ boost::shared_ptr<Evoral::Control> c = data().control (param);
if (c)
c->set_value(val);
@@ -392,14 +392,14 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
nframes_t now = _session.transport_frame ();
nframes_t end = now + nframes;
- Glib::Mutex::Lock lm (_control_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock lm (data().control_lock(), Glib::TRY_LOCK);
if (!lm.locked()) {
connect_and_run (bufs, nframes, offset, false);
return;
}
- if (!find_next_event (now, end, next_event)) {
+ if (!data().find_next_event (now, end, next_event)) {
/* no events have a time within the relevant range */
@@ -417,7 +417,7 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
offset += cnt;
now += cnt;
- if (!find_next_event (now, end, next_event)) {
+ if (!data().find_next_event (now, end, next_event)) {
break;
}
}
@@ -636,7 +636,7 @@ PluginInsert::state (bool full)
child->add_child_nocopy (automation_list (*x).state (full));
autonode->add_child_nocopy (*child);
*/
- autonode->add_child_nocopy (((AutomationList*)control(*x)->list().get())->state (full));
+ autonode->add_child_nocopy (((AutomationList*)data().control(*x)->list().get())->state (full));
}
node.add_child_nocopy (*autonode);
@@ -760,7 +760,7 @@ PluginInsert::set_state(const XMLNode& node)
}
boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(
- control(Parameter(PluginAutomation, port_id), true));
+ data().control(Parameter(PluginAutomation, port_id), true));
if (!child->children().empty()) {
c->alist()->set_state (*child->children().front());
@@ -847,7 +847,7 @@ PluginInsert::type ()
}
PluginInsert::PluginControl::PluginControl (PluginInsert& p, boost::shared_ptr<AutomationList> list)
- : AutomationControl (p.session(), list, p.describe_parameter(list->parameter()))
+ : AutomationControl (p.session(), list->parameter(), list, p.describe_parameter(list->parameter()))
, _plugin (p)
, _list (list)
{
diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc
index 486a75703b..82591effa4 100644
--- a/libs/ardour/processor.cc
+++ b/libs/ardour/processor.cc
@@ -59,7 +59,8 @@ sigc::signal<void,Processor*> Processor::ProcessorCreated;
const string Processor::state_node_name = "Processor";
Processor::Processor(Session& session, const string& name, Placement p)
- : Automatable(session, name)
+ : SessionObject(session, name)
+ , AutomatableControls(session)
, _active(false)
, _next_ab_is_active(false)
, _configured(false)
diff --git a/libs/ardour/quantize.cc b/libs/ardour/quantize.cc
index ccbda9711a..ff8925edd9 100644
--- a/libs/ardour/quantize.cc
+++ b/libs/ardour/quantize.cc
@@ -69,7 +69,8 @@ Quantize::run (boost::shared_ptr<Region> r)
double q_frames = _q * (m.frames_per_bar(t, session.frame_rate()) / (double)m.beats_per_bar());
- for (MidiModel::Notes::iterator i = model->notes().begin(); i != model->notes().end(); ++i) {
+ for (Evoral::Sequence::Notes::iterator i = model->notes().begin();
+ i != model->notes().end(); ++i) {
const double new_time = lrint((*i)->time() / q_frames) * q_frames;
double new_dur = lrint((*i)->duration() / q_frames) * q_frames;
if (new_dur == 0.0)
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 25435024b3..8693b7df8e 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -57,7 +57,7 @@ sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChan
/* derived-from-derived constructor (no sources in constructor) */
Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
- : Automatable(s, name)
+ : SessionObject(s, name)
, _type(type)
, _flags(flags)
, _start(start)
@@ -79,7 +79,7 @@ Region::Region (Session& s, nframes_t start, nframes_t length, const string& nam
/** Basic Region constructor (single source) */
Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
- : Automatable(src->session(), name)
+ : SessionObject(src->session(), name)
, _type(type)
, _flags(flags)
, _start(start)
@@ -112,7 +112,7 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
/** Basic Region constructor (many sources) */
Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
- : Automatable(srcs.front()->session(), name)
+ : SessionObject(srcs.front()->session(), name)
, _type(type)
, _flags(flags)
, _start(start)
@@ -150,7 +150,7 @@ Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const
/** Create a new Region from part of an existing one */
Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
- : Automatable(other->session(), name)
+ : SessionObject(other->session(), name)
, _type(other->data_type())
, _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
, _start(other->_start + offset)
@@ -199,7 +199,7 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
/** Pure copy constructor */
Region::Region (boost::shared_ptr<const Region> other)
- : Automatable(other->session(), other->name())
+ : SessionObject(other->session(), other->name())
, _type(other->data_type())
, _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
, _start(other->_start)
@@ -247,7 +247,7 @@ Region::Region (boost::shared_ptr<const Region> other)
}
Region::Region (const SourceList& srcs, const XMLNode& node)
- : Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
+ : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL) // to be loaded from XML
, _flags(Flag(0))
, _start(0)
@@ -288,7 +288,7 @@ Region::Region (const SourceList& srcs, const XMLNode& node)
}
Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
- : Automatable(src->session(), X_("error: XML did not reset this"))
+ : SessionObject(src->session(), X_("error: XML did not reset this"))
, _type(DataType::NIL)
, _flags(Flag(0))
, _start(0)
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 79d2b4f9b6..7cf6c4ef36 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -2528,7 +2528,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
apply_gain_automation = false;
{
- Glib::Mutex::Lock am (_control_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
if (am.locked() && _session.transport_rolling()) {