summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/audioregion.h22
-rw-r--r--libs/ardour/ardour/automatable.h48
-rw-r--r--libs/ardour/ardour/automation_event.h170
-rw-r--r--libs/ardour/ardour/crossfade.h8
-rw-r--r--libs/ardour/ardour/curve.h36
-rw-r--r--libs/ardour/ardour/gain.h2
-rw-r--r--libs/ardour/ardour/io.h34
-rw-r--r--libs/ardour/ardour/ladspa_plugin.h4
-rw-r--r--libs/ardour/ardour/panner.h14
-rw-r--r--libs/ardour/ardour/param_id.h137
-rw-r--r--libs/ardour/ardour/plugin.h7
-rw-r--r--libs/ardour/ardour/plugin_insert.h16
-rw-r--r--libs/ardour/ardour/types.h10
-rw-r--r--libs/ardour/audio_track.cc10
-rw-r--r--libs/ardour/audioregion.cc44
-rw-r--r--libs/ardour/automatable.cc242
-rw-r--r--libs/ardour/automation_event.cc536
-rw-r--r--libs/ardour/crossfade.cc16
-rw-r--r--libs/ardour/curve.cc126
-rw-r--r--libs/ardour/enums.cc4
-rw-r--r--libs/ardour/gain.cc6
-rw-r--r--libs/ardour/insert.cc7
-rw-r--r--libs/ardour/io.cc136
-rw-r--r--libs/ardour/ladspa_plugin.cc14
-rw-r--r--libs/ardour/panner.cc6
-rw-r--r--libs/ardour/plugin.cc2
-rw-r--r--libs/ardour/plugin_insert.cc122
-rw-r--r--libs/ardour/route.cc37
-rw-r--r--libs/ardour/send.cc2
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc2
30 files changed, 1011 insertions, 809 deletions
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index f844d45ef1..db763876b0 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -67,9 +67,9 @@ class AudioRegion : public Region
bool fade_in_active () const { return _flags & Region::FadeIn; }
bool fade_out_active () const { return _flags & Region::FadeOut; }
- Curve& fade_in() { return _fade_in; }
- Curve& fade_out() { return _fade_out; }
- Curve& envelope() { return _envelope; }
+ AutomationList& fade_in() { return _fade_in; }
+ AutomationList& fade_out() { return _fade_out; }
+ AutomationList& envelope() { return _envelope; }
virtual nframes_t read_peaks (PeakData *buf, nframes_t npeaks,
nframes_t offset, nframes_t cnt,
@@ -162,14 +162,14 @@ class AudioRegion : public Region
void source_offset_changed ();
void listen_to_my_curves ();
- mutable Curve _fade_in;
- FadeShape _fade_in_shape;
- mutable Curve _fade_out;
- FadeShape _fade_out_shape;
- mutable Curve _envelope;
- gain_t _scale_amplitude;
- uint32_t _fade_in_disabled;
- uint32_t _fade_out_disabled;
+ mutable AutomationList _fade_in;
+ FadeShape _fade_in_shape;
+ mutable AutomationList _fade_out;
+ FadeShape _fade_out_shape;
+ mutable AutomationList _envelope;
+ gain_t _scale_amplitude;
+ uint32_t _fade_in_disabled;
+ uint32_t _fade_out_disabled;
protected:
/* default constructor for derived (compound) types */
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index c6621b9780..f6d6d86ed0 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -24,6 +24,7 @@
#include <map>
#include <ardour/session_object.h>
#include <ardour/automation_event.h>
+#include <ardour/param_id.h>
namespace ARDOUR {
@@ -36,28 +37,46 @@ public:
virtual ~Automatable() {}
- virtual AutomationList& automation_list(uint32_t n);
+ // shorthand for gain, pan, etc
+ inline AutomationList* automation_list(AutomationType type, bool create_if_missing=false) {
+ return automation_list(ParamID(type), create_if_missing);
+ }
- virtual void automation_snapshot (nframes_t now) {};
+ virtual AutomationList* automation_list(ParamID id, bool create_if_missing=false);
+ virtual const AutomationList* automation_list(ParamID id) const;
+
+ virtual void add_automation_parameter(AutomationList* al);
+
+ virtual void automation_snapshot(nframes_t now) {};
virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
- virtual string describe_parameter(uint32_t which);
- virtual float default_parameter_value(uint32_t which) { return 1.0f; }
+ virtual string describe_parameter(ParamID param);
+ virtual float default_parameter_value(ParamID param) { return 1.0f; }
+
+ virtual void clear_automation();
+
+ AutoState get_parameter_automation_state (ParamID param);
+ virtual void set_parameter_automation_state (ParamID param, AutoState);
+
+ AutoStyle get_parameter_automation_style (ParamID param);
+ void set_parameter_automation_style (ParamID param, AutoStyle);
+
+ void protect_automation ();
- void what_has_automation(std::set<uint32_t>&) const;
- void what_has_visible_automation(std::set<uint32_t>&) const;
- const std::set<uint32_t>& what_can_be_automated() const { return _can_automate_list; }
+ void what_has_automation(std::set<ParamID>&) const;
+ void what_has_visible_automation(std::set<ParamID>&) const;
+ const std::set<ParamID>& what_can_be_automated() const { return _can_automate_list; }
- void mark_automation_visible(uint32_t, bool);
+ void mark_automation_visible(ParamID, bool);
protected:
- void can_automate(uint32_t);
+ void can_automate(ParamID);
- virtual void automation_list_creation_callback(uint32_t, AutomationList&) {}
+ virtual void automation_list_creation_callback(ParamID, AutomationList&) {}
- int set_automation_state(const XMLNode&);
+ int set_automation_state(const XMLNode&, ParamID default_param);
XMLNode& get_automation_state();
int load_automation (const std::string& path);
@@ -65,10 +84,9 @@ protected:
mutable Glib::Mutex _automation_lock;
- // FIXME: map with int keys is a bit silly. this could be O(1)
- std::map<uint32_t,AutomationList*> _parameter_automation;
- std::set<uint32_t> _visible_parameter_automation;
- std::set<uint32_t> _can_automate_list;
+ std::map<ParamID,AutomationList*> _parameter_automation;
+ std::set<ParamID> _visible_parameter_automation;
+ std::set<ParamID> _can_automate_list;
nframes_t _last_automation_snapshot;
};
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index f04dcdc112..af1a3cb704 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -32,35 +32,39 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
+#include <ardour/param_id.h>
namespace ARDOUR {
-
+
+class Curve;
+
struct ControlEvent {
- double when;
- double value;
-
+
ControlEvent (double w, double v)
- : when (w), value (v) { }
- ControlEvent (const ControlEvent& other)
- : when (other.when), value (other.value) {}
+ : when (w), value (v) {
+ coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
+ }
- virtual ~ControlEvent() {}
+ ControlEvent (const ControlEvent& other)
+ : when (other.when), value (other.value) {
+ coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
+ }
-// bool operator==(const ControlEvent& other) {
-// return value == other.value && when == other.when;
-// }
-
+ double when;
+ double value;
+ double coeff[4]; ///< Used by Curve
};
+
class AutomationList : public PBD::StatefulDestructible
{
public:
- typedef std::list<ControlEvent*> AutomationEventList;
- typedef AutomationEventList::iterator iterator;
- typedef AutomationEventList::const_iterator const_iterator;
+ typedef std::list<ControlEvent*> EventList;
+ typedef EventList::iterator iterator;
+ typedef EventList::const_iterator const_iterator;
- AutomationList (double default_value);
- AutomationList (const XMLNode&);
+ AutomationList (ParamID id, double min_val, double max_val, double default_val);
+ AutomationList (const XMLNode&, ParamID id);
~AutomationList();
AutomationList (const AutomationList&);
@@ -68,14 +72,17 @@ class AutomationList : public PBD::StatefulDestructible
AutomationList& operator= (const AutomationList&);
bool operator== (const AutomationList&);
+ ParamID param_id() const { return _param_id; }
+ void set_param_id(ParamID id) { _param_id = id; }
+
void freeze();
void thaw ();
- AutomationEventList::size_type size() const { return events.size(); }
- bool empty() const { return events.empty(); }
+ EventList::size_type size() const { return _events.size(); }
+ bool empty() const { return _events.empty(); }
void reset_default (double val) {
- default_value = val;
+ _default_value = val;
}
void clear ();
@@ -111,7 +118,7 @@ class AutomationList : public PBD::StatefulDestructible
sigc::signal<void> automation_style_changed;
void set_automation_style (AutoStyle m);
- AutoStyle automation_style() const { return _style; }
+ AutoStyle automation_style() const { return _style; }
sigc::signal<void> automation_state_changed;
bool automation_playback() const {
@@ -126,29 +133,29 @@ class AutomationList : public PBD::StatefulDestructible
bool touching() const { return _touching; }
void set_yrange (double min, double max) {
- min_yval = min;
- max_yval = max;
+ _min_yval = min;
+ _max_yval = max;
}
- double get_max_y() const { return max_yval; }
- double get_min_y() const { return min_yval; }
+ double get_max_y() const { return _max_yval; }
+ double get_min_y() const { return _min_yval; }
void truncate_end (double length);
void truncate_start (double length);
- iterator begin() { return events.begin(); }
- iterator end() { return events.end(); }
+ iterator begin() { return _events.begin(); }
+ iterator end() { return _events.end(); }
- ControlEvent* back() { return events.back(); }
- ControlEvent* front() { return events.front(); }
+ ControlEvent* back() { return _events.back(); }
+ ControlEvent* front() { return _events.front(); }
- const_iterator const_begin() const { return events.begin(); }
- const_iterator const_end() const { return events.end(); }
+ const_iterator const_begin() const { return _events.begin(); }
+ const_iterator const_end() const { return _events.end(); }
std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
(obj.*method)(*this);
}
@@ -160,16 +167,16 @@ class AutomationList : public PBD::StatefulDestructible
XMLNode& serialize_events ();
void set_max_xval (double);
- double get_max_xval() const { return max_xval; }
+ double get_max_xval() const { return _max_xval; }
double eval (double where) {
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
return unlocked_eval (where);
}
double rt_safe_eval (double where, bool& ok) {
- Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
if ((ok = lm.locked())) {
return unlocked_eval (where);
@@ -183,65 +190,66 @@ class AutomationList : public PBD::StatefulDestructible
return a->when < b->when;
}
};
-
- static sigc::signal<void, AutomationList*> AutomationListCreated;
-
- protected:
-
- AutomationEventList events;
- mutable Glib::Mutex lock;
- int8_t _frozen;
- bool changed_when_thawed;
- bool _dirty;
-
+
struct LookupCache {
double left; /* leftmost x coordinate used when finding "range" */
- std::pair<AutomationList::iterator,AutomationList::iterator> range;
+ std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
};
- mutable LookupCache lookup_cache;
-
- AutoState _state;
- AutoStyle _style;
- bool _touching;
- bool _new_touch;
- double max_xval;
- double min_yval;
- double max_yval;
- double default_value;
- bool sort_pending;
-
- iterator rt_insertion_point;
- double rt_pos;
-
- void maybe_signal_changed ();
- void mark_dirty ();
- void _x_scale (double factor);
-
- /* called by type-specific unlocked_eval() to handle
- common case of 0, 1 or 2 control points.
- */
+ static sigc::signal<void, AutomationList*> AutomationListCreated;
- double shared_eval (double x);
+ const EventList& events() const { return _events; }
+ double default_value() const { return _default_value; }
- /* called by shared_eval() to handle any case of
- 3 or more control points.
- */
-
- virtual double multipoint_eval (double x);
+ // teeny const violations for Curve
+ mutable sigc::signal<void> Dirty;
+ Glib::Mutex& lock() const { return _lock; }
+ LookupCache& lookup_cache() const { return _lookup_cache; }
+
+ /** Called by locked entry point and various private
+ * locations where we already hold the lock.
+ *
+ * FIXME: Should this be private? Curve needs it..
+ */
+ double unlocked_eval (double x) const;
- /* called by locked entry point and various private
- locations where we already hold the lock.
- */
+ Curve& curve() { return *_curve; }
+ const Curve& curve() const { return *_curve; }
- virtual double unlocked_eval (double where);
+ protected:
- virtual ControlEvent* point_factory (double,double) const;
- virtual ControlEvent* point_factory (const ControlEvent&) const;
+ /** Called by unlocked_eval() to handle cases of 3 or more control points.
+ */
+ virtual double multipoint_eval (double x) const;
AutomationList* cut_copy_clear (double, double, int op);
int deserialize_events (const XMLNode&);
+
+ void maybe_signal_changed ();
+ void mark_dirty ();
+ void _x_scale (double factor);
+
+ mutable LookupCache _lookup_cache;
+
+ ParamID _param_id;
+ EventList _events;
+ mutable Glib::Mutex _lock;
+ int8_t _frozen;
+ bool _changed_when_thawed;
+ AutoState _state;
+ AutoStyle _style;
+ bool _touching;
+ bool _new_touch;
+ double _max_xval;
+ double _min_yval;
+ double _max_yval;
+ double _default_value;
+ bool _sort_pending;
+ iterator _rt_insertion_point;
+ double _rt_pos;
+
+ Curve* _curve;
};
} // namespace
diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h
index 61a30f1c0f..78a137bde3 100644
--- a/libs/ardour/ardour/crossfade.h
+++ b/libs/ardour/ardour/crossfade.h
@@ -124,8 +124,8 @@ class Crossfade : public ARDOUR::AudioRegion
bool can_follow_overlap() const;
void set_follow_overlap (bool yn);
- Curve& fade_in() { return _fade_in; }
- Curve& fade_out() { return _fade_out; }
+ AutomationList& fade_in() { return _fade_in; }
+ AutomationList& fade_out() { return _fade_out; }
nframes_t set_length (nframes_t);
@@ -157,8 +157,8 @@ class Crossfade : public ARDOUR::AudioRegion
int32_t layer_relation;
- mutable Curve _fade_in;
- mutable Curve _fade_out;
+ mutable AutomationList _fade_in;
+ mutable AutomationList _fade_out;
static Sample* crossfade_buffer_out;
static Sample* crossfade_buffer_in;
diff --git a/libs/ardour/ardour/curve.h b/libs/ardour/ardour/curve.h
index 605eda2e4b..b96bb5c78e 100644
--- a/libs/ardour/ardour/curve.h
+++ b/libs/ardour/ardour/curve.h
@@ -30,50 +30,30 @@
namespace ARDOUR {
-struct CurvePoint : public ControlEvent
-{
- double coeff[4];
-
- CurvePoint (double w, double v)
- : ControlEvent (w, v) {
-
- coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
- }
-
- ~CurvePoint() {}
-};
-
-class Curve : public AutomationList
+class Curve
{
public:
- Curve (double min_yval, double max_yval, double defaultvalue, bool nostate = false);
+ Curve (const AutomationList& al);
~Curve ();
Curve (const Curve& other);
- Curve (const Curve& other, double start, double end);
- Curve (const XMLNode&);
+ //Curve (const Curve& other, double start, double end);
+ /*Curve (const XMLNode&, ParamID id);*/
bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen);
void get_vector (double x0, double x1, float *arg, int32_t veclen);
- AutomationEventList::iterator closest_control_point_before (double xval);
- AutomationEventList::iterator closest_control_point_after (double xval);
-
void solve ();
- static sigc::signal<void, Curve*> CurveCreated;
-
- protected:
- ControlEvent* point_factory (double,double) const;
- ControlEvent* point_factory (const ControlEvent&) const;
-
private:
- AutomationList::iterator last_bound;
-
double unlocked_eval (double where);
double multipoint_eval (double x);
void _get_vector (double x0, double x1, float *arg, int32_t veclen);
+ const AutomationList& _list;
+
+ void on_list_dirty() { _dirty = true; }
+ bool _dirty;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/gain.h b/libs/ardour/ardour/gain.h
index 5832f71101..e57cfdc0d7 100644
--- a/libs/ardour/ardour/gain.h
+++ b/libs/ardour/ardour/gain.h
@@ -25,7 +25,7 @@
namespace ARDOUR {
-struct Gain : public Curve {
+struct Gain : public AutomationList {
Gain();
Gain (const Gain&);
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 3952d14c0e..1592ac7cac 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -34,7 +34,7 @@
#include <pbd/controllable.h>
#include <ardour/ardour.h>
-#include <ardour/session_object.h>
+#include <ardour/automatable.h>
#include <ardour/utils.h>
#include <ardour/curve.h>
#include <ardour/types.h>
@@ -64,9 +64,8 @@ class BufferSet;
* An IO can contain ports of varying types, making routes/inserts/etc with
* varied combinations of types (eg MIDI and audio) possible.
*/
-class IO : public SessionObject
+class IO : public Automatable
{
-
public:
static const string state_node_name;
@@ -227,22 +226,15 @@ class IO : public SessionObject
}
void clear_automation ();
-
- virtual void set_gain_automation_state (AutoState);
- AutoState gain_automation_state() const { return _gain_automation_curve.automation_state(); }
- //sigc::signal<void> gain_automation_state_changed;
-
- virtual void set_gain_automation_style (AutoStyle);
- AutoStyle gain_automation_style () const { return _gain_automation_curve.automation_style(); }
- //sigc::signal<void> gain_automation_style_changed;
+
+ void set_parameter_automation_state (ParamID, AutoState);
virtual void transport_stopped (nframes_t now); // interface: matches Insert
void automation_snapshot (nframes_t now); // interface: matches Automatable
- ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
-
- void start_gain_touch ();
- void end_gain_touch ();
+ // FIXME: these will probably become unsafe in the near future
+ ARDOUR::AutomationList& gain_automation() { return *automation_list(GainAutomation); }
+ const ARDOUR::AutomationList& gain_automation() const { return *automation_list(GainAutomation); }
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
@@ -299,16 +291,12 @@ class IO : public SessionObject
nframes_t last_automation_snapshot;
static nframes_t _automation_interval;
- AutoState _gain_automation_state;
- AutoStyle _gain_automation_style;
+ /*AutoState _gain_automation_state;
+ AutoStyle _gain_automation_style;*/
- bool apply_gain_automation;
- Curve _gain_automation_curve;
+ bool apply_gain_automation;
+ //Curve _gain_automation_curve;
- Glib::Mutex automation_lock;
-
- virtual int set_automation_state (const XMLNode&);
- virtual XMLNode& get_automation_state ();
virtual int load_automation (std::string path);
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
diff --git a/libs/ardour/ardour/ladspa_plugin.h b/libs/ardour/ardour/ladspa_plugin.h
index f1f1bb8811..5c15632391 100644
--- a/libs/ardour/ardour/ladspa_plugin.h
+++ b/libs/ardour/ardour/ladspa_plugin.h
@@ -63,7 +63,7 @@ class LadspaPlugin : public ARDOUR::Plugin
void set_parameter (uint32_t port, float val);
float get_parameter (uint32_t port) const;
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
- std::set<uint32_t> automatable() const;
+ std::set<ParamID> automatable() const;
uint32_t nth_parameter (uint32_t port, bool& ok) const;
void activate () {
if (descriptor->activate) {
@@ -85,7 +85,7 @@ class LadspaPlugin : public ARDOUR::Plugin
int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset);
void store_state (ARDOUR::PluginState&);
void restore_state (ARDOUR::PluginState&);
- string describe_parameter (uint32_t);
+ string describe_parameter (ParamID);
string state_node_name() const { return "ladspa"; }
void print_parameter (uint32_t, char*, uint32_t len) const;
diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h
index 0e5ab68525..af3cda94e2 100644
--- a/libs/ardour/ardour/panner.h
+++ b/libs/ardour/ardour/panner.h
@@ -81,8 +81,9 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
/* XXX this is wrong. for multi-dimensional panners, there
must surely be more than 1 automation curve.
*/
+ /* TODO: Panner is-a Automation solves this */
- virtual Curve& automation() = 0;
+ virtual AutomationList& automation() = 0;
sigc::signal<void> Changed; /* for position */
sigc::signal<void> StateChanged; /* for mute */
@@ -149,7 +150,8 @@ class BaseStereoPanner : public StreamPanner
void set_automation_state (AutoState);
void set_automation_style (AutoStyle);
- Curve& automation() { return _automation; }
+ /* TODO: StreamPanner is-a Automatable? */
+ AutomationList& automation() { return _automation; }
/* old school automation loading */
@@ -163,7 +165,7 @@ class BaseStereoPanner : public StreamPanner
float left_interp;
float right_interp;
- Curve _automation;
+ AutomationList _automation;
};
class EqualPowerStereoPanner : public BaseStereoPanner
@@ -203,8 +205,10 @@ class Multi2dPanner : public StreamPanner
/* XXX this is wrong. for multi-dimensional panners, there
must surely be more than 1 automation curve.
*/
+
+ /* TODO: StreamPanner is-a Automatable? */
- Curve& automation() { return _automation; }
+ AutomationList& automation() { return _automation; }
void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes);
void distribute_automated (AudioBuffer& src, BufferSet& obufs,
@@ -222,7 +226,7 @@ class Multi2dPanner : public StreamPanner
int load (istream&, string path, uint32_t&);
private:
- Curve _automation;
+ AutomationList _automation;
void update ();
};
diff --git a/libs/ardour/ardour/param_id.h b/libs/ardour/ardour/param_id.h
new file mode 100644
index 0000000000..eb5563b06d
--- /dev/null
+++ b/libs/ardour/ardour/param_id.h
@@ -0,0 +1,137 @@
+/*
+ Copyright (C) 2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __ardour_param_id_h__
+#define __ardour_param_id_h__
+
+#include <string>
+#include <pbd/compose.h>
+#include <pbd/error.h>
+#include <ardour/types.h>
+
+namespace ARDOUR {
+
+
+/** ID of an automatable parameter.
+ *
+ * A given automatable object has a number of automatable parameters. This is
+ * the unique ID for those parameters. Anything automatable (AutomationList,
+ * Curve) must have an ID unique with respect to it's Automatable parent.
+ *
+ * A parameter ID has two parts, a type and an int (only used by some types).
+ *
+ * This is a bit more ugly than it could be, due to using the existing/legacy
+ * ARDOUR::AutomationType: GainAutomation, PanAutomation, SoloAutomation,
+ * and MuteAutomation use only the type(), but PluginAutomation and
+ * MidiCCAutomation use the id() as port number and CC number, respectively.
+ *
+ * Future types may use a string or URI or whatever, as long as these are
+ * comparable anything may be added. ints are best as these should be fast to
+ * copy and compare with one another.
+ */
+class ParamID
+{
+public:
+ inline ParamID(AutomationType type = NullAutomation, uint32_t id=0) : _type(type), _id(id) {}
+
+ /** Construct an ParamID from a string returned from ParamID::to_string
+ * (AutomationList automation-id property)
+ */
+ ParamID(const std::string& str) : _type(NullAutomation), _id(0) {
+ if (str == "gain") {
+ _type = GainAutomation;
+ } else if (str == "pan") {
+ _type = PanAutomation;
+ } else if (str == "solo") {
+ _type = SoloAutomation;
+ } else if (str == "mute") {
+ _type = MuteAutomation;
+ } else if (str == "fadein") {
+ _type = FadeInAutomation;
+ } else if (str == "fadeout") {
+ _type = FadeOutAutomation;
+ } else if (str == "envelope") {
+ _type = EnvelopeAutomation;
+ } else if (str.length() > 10 && str.substr(0, 10) == "parameter-") {
+ _type = PluginAutomation;
+ _id = atoi(str.c_str()+10);
+ PBD::info << "Parameter: " << str << " -> " << _id << endl;
+ } else if (str.length() > 7 && str.substr(0, 7) == "midicc-") {
+ _type = MidiCCAutomation;
+ _id = atoi(str.c_str()+7);
+ PBD::info << "MIDI CC: " << str << " -> " << _id << endl;
+ } else {
+ PBD::warning << "Unknown ParamID '" << str << "'" << endmsg;
+ }
+ }
+
+ inline AutomationType type() const { return _type; }
+ inline uint32_t id() const { return _id; }
+
+ inline bool operator==(const ParamID& id) const
+ { return (_type == id._type && _id == id._id); }
+
+ /** Arbitrary but fixed ordering, so we're comparable (usable in std::map) */
+ inline bool operator<(const ParamID& id) const {
+ // FIXME: branch a performance problem? #ifdef DEBUG?
+ if (_type == NullAutomation)
+ PBD::warning << "Uninitialized ParamID compared." << endmsg;
+ return (_type < id._type || _id < id._id);
+ }
+
+ inline operator bool() const { return (_type != 0); }
+
+ /** Unique string representation, suitable as an XML property value.
+ * e.g. <AutomationList automation-id="whatthisreturns">
+ */
+ inline std::string to_string() const {
+ if (_type == GainAutomation) {
+ return "gain";
+ } else if (_type == PanAutomation) {
+ return "pan";
+ } else if (_type == SoloAutomation) {
+ return "solo";
+ } else if (_type == MuteAutomation) {
+ return "mute";
+ } else if (_type == FadeInAutomation) {
+ return "fadein";
+ } else if (_type == FadeOutAutomation) {
+ return "fadeout";
+ } else if (_type == EnvelopeAutomation) {
+ return "envelope";
+ } else if (_type == PluginAutomation) {
+ return string_compose("parameter-%1", _id);
+ } else if (_type == MidiCCAutomation) {
+ return string_compose("midicc-%1", _id);
+ } else {
+ PBD::warning << "Uninitialized ParamID to_string() called." << endmsg;
+ return "";
+ }
+ }
+
+private:
+ // default copy constructor is ok
+ AutomationType _type;
+ uint32_t _id;
+};
+
+
+} // namespace ARDOUR
+
+#endif // __ardour_param_id_h__
+
diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h
index b1a2823b33..22c0862202 100644
--- a/libs/ardour/ardour/plugin.h
+++ b/libs/ardour/ardour/plugin.h
@@ -31,6 +31,7 @@
#include <ardour/chan_count.h>
#include <ardour/plugin_state.h>
#include <ardour/cycles.h>
+#include <ardour/param_id.h>
#include <vector>
#include <set>
@@ -121,10 +122,10 @@ class Plugin : public PBD::StatefulDestructible
virtual int connect_and_run (BufferSet& bufs, uint32_t& in, uint32_t& out, nframes_t nframes, nframes_t offset) = 0;
- virtual std::set<uint32_t> automatable() const = 0;
+ virtual std::set<ParamID> automatable() const = 0;
virtual void store_state (ARDOUR::PluginState&) = 0;
virtual void restore_state (ARDOUR::PluginState&) = 0;
- virtual string describe_parameter (uint32_t) = 0;
+ virtual string describe_parameter (ParamID) = 0;
virtual string state_node_name() const = 0;
virtual void print_parameter (uint32_t, char*, uint32_t len) const = 0;
@@ -139,7 +140,7 @@ class Plugin : public PBD::StatefulDestructible
virtual bool has_editor() const = 0;
- sigc::signal<void,uint32_t,float> ParameterChanged;
+ sigc::signal<void,ParamID,float> ParameterChanged;
PBD::Controllable *get_nth_control (uint32_t);
diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h
index 4acacae7f5..df0460af84 100644
--- a/libs/ardour/ardour/plugin_insert.h
+++ b/libs/ardour/ardour/plugin_insert.h
@@ -76,13 +76,9 @@ class PluginInsert : public Insert
bool is_generator() const;
- void set_parameter (uint32_t port, float val);
+ void set_parameter (ParamID param, float val);
- AutoState get_port_automation_state (uint32_t port);
- void set_port_automation_state (uint32_t port, AutoState);
- void protect_automation ();
-
- float default_parameter_value (uint32_t which);
+ float default_parameter_value (ParamID param);
boost::shared_ptr<Plugin> plugin(uint32_t num=0) const {
if (num < _plugins.size()) {
@@ -94,7 +90,7 @@ class PluginInsert : public Insert
PluginType type ();
- string describe_parameter (uint32_t);
+ string describe_parameter (ParamID param);
nframes_t latency();
@@ -103,7 +99,7 @@ class PluginInsert : public Insert
private:
- void parameter_changed (uint32_t, float);
+ void parameter_changed (ParamID, float);
std::vector<boost::shared_ptr<Plugin> > _plugins;
@@ -112,8 +108,8 @@ class PluginInsert : public Insert
void init ();
void set_automatable ();
- void auto_state_changed (uint32_t which);
- void automation_list_creation_callback (uint32_t, AutomationList&);
+ void auto_state_changed (ParamID which);
+ void automation_list_creation_callback (ParamID, AutomationList&);
int32_t count_for_configuration (ChanCount in, ChanCount out) const;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index d5f10410db..b2f13def81 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -93,12 +93,20 @@ namespace ARDOUR {
OverlapType coverage (nframes_t start_a, nframes_t end_a,
nframes_t start_b, nframes_t end_b);
+ /** See param_id.h
+ * XXX: I don't think/hope these hex values matter anymore.
+ */
enum AutomationType {
+ NullAutomation = 0x0,
GainAutomation = 0x1,
PanAutomation = 0x2,
PluginAutomation = 0x4,
SoloAutomation = 0x8,
- MuteAutomation = 0x10
+ MuteAutomation = 0x10,
+ MidiCCAutomation = 0x20,
+ FadeInAutomation = 0x40,
+ FadeOutAutomation = 0x80,
+ EnvelopeAutomation = 0x100
};
enum AutoState {
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index b08990c2ab..151b434c6b 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -599,10 +599,10 @@ 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 (automation_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
- if (am.locked() && _gain_automation_curve.automation_playback()) {
- apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+ if (am.locked() && gain_automation().automation_playback()) {
+ apply_gain_automation = gain_automation().curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
}
}
@@ -696,9 +696,9 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
}
}
- if (_gain_automation_curve.automation_state() == Play) {
+ if (IO::gain_automation().automation_state() == Play) {
- _gain_automation_curve.get_vector (start, start + nframes, gain_automation, nframes);
+ IO::gain_automation().curve().get_vector (start, start + nframes, gain_automation, nframes);
for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
Sample *b = bi->data();
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 55a1879726..a7a5fca912 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -73,9 +73,9 @@ AudioRegion::init ()
/* constructor for use by derived types only */
AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name)
: Region (start, length, name, DataType::AUDIO),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0),
+ _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0),
+ _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
{
init ();
}
@@ -83,9 +83,9 @@ AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name)
/** 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)),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0),
+ _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0),
+ _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
{
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
@@ -98,9 +98,9 @@ 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)
- , _fade_in (0.0, 2.0, 1.0, false)
- , _fade_out (0.0, 2.0, 1.0, false)
- , _envelope (0.0, 2.0, 1.0, false)
+ , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
+ , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
+ , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
{
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
@@ -113,9 +113,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
/* Basic AudioRegion constructor (many channels) */
AudioRegion::AudioRegion (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)
- , _fade_in (0.0, 2.0, 1.0, false)
- , _fade_out (0.0, 2.0, 1.0, false)
- , _envelope (0.0, 2.0, 1.0, false)
+ , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
+ , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
+ , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
{
init ();
}
@@ -179,9 +179,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
: Region (src, node)
- , _fade_in (0.0, 2.0, 1.0, false)
- , _fade_out (0.0, 2.0, 1.0, false)
- , _envelope (0.0, 2.0, 1.0, false)
+ , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
+ , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
+ , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
{
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs) {
@@ -200,10 +200,10 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
}
AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
- : Region (srcs, node),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ : Region (srcs, node)
+ , _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0)
+ , _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)
+ , _envelope (ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)
{
set_default_fades ();
_scale_amplitude = 1.0;
@@ -405,7 +405,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
limit = min (to_read, fade_in_length - internal_offset);
- _fade_in.get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
+ _fade_in.curve().get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
for (nframes_t n = 0; n < limit; ++n) {
mixdown_buffer[n] *= gain_buffer[n];
@@ -447,7 +447,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
nframes_t fade_offset = fade_interval_start - internal_offset;
- _fade_out.get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
+ _fade_out.curve().get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
mixdown_buffer[m] *= gain_buffer[n];
@@ -459,7 +459,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
/* Regular gain curves */
if (envelope_active()) {
- _envelope.get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
+ _envelope.curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
if (_scale_amplitude != 1.0f) {
for (nframes_t n = 0; n < to_read; ++n) {
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index 2ce553a188..40ab7af769 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -62,7 +62,7 @@ Automatable::old_set_automation_state (const XMLNode& node)
if (sstr.fail()) {
break;
}
- mark_automation_visible (what, true);
+ mark_automation_visible (ParamID(PluginAutomation, what), true);
}
}
@@ -88,7 +88,7 @@ Automatable::load_automation (const string& path)
}
Glib::Mutex::Lock lm (_automation_lock);
- set<uint32_t> tosave;
+ set<ParamID> tosave;
_parameter_automation.clear ();
while (in) {
@@ -100,9 +100,10 @@ Automatable::load_automation (const string& path)
in >> when; if (!in) goto bad;
in >> value; if (!in) goto bad;
- AutomationList& al = automation_list (port);
- al.add (when, value);
- tosave.insert (port);
+ /* FIXME: this is legacy and only used for plugin inserts? I think? */
+ AutomationList* al = automation_list (ParamID(PluginAutomation, port), true);
+ al->add (when, value);
+ tosave.insert (ParamID(PluginAutomation, port));
}
return 0;
@@ -113,12 +114,27 @@ Automatable::load_automation (const string& path)
return -1;
}
+void
+Automatable::add_automation_parameter(AutomationList* al)
+{
+ _parameter_automation[al->param_id()] = al;
+
+ /* let derived classes do whatever they need with this */
+ automation_list_creation_callback (al->param_id(), *al);
+
+ cerr << _name << ": added (visible, can_automate) parameter " << al->param_id().to_string() << ", # params = "
+ << _parameter_automation.size() << endl;
+
+ // FIXME: sane default behaviour?
+ _visible_parameter_automation.insert(al->param_id());
+ _can_automate_list.insert(al->param_id());
+}
void
-Automatable::what_has_automation (set<uint32_t>& s) const
+Automatable::what_has_automation (set<ParamID>& s) const
{
Glib::Mutex::Lock lm (_automation_lock);
- map<uint32_t,AutomationList*>::const_iterator li;
+ map<ParamID,AutomationList*>::const_iterator li;
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
s.insert ((*li).first);
@@ -126,49 +142,79 @@ Automatable::what_has_automation (set<uint32_t>& s) const
}
void
-Automatable::what_has_visible_automation (set<uint32_t>& s) const
+Automatable::what_has_visible_automation (set<ParamID>& s) const
{
Glib::Mutex::Lock lm (_automation_lock);
- set<uint32_t>::const_iterator li;
+ set<ParamID>::const_iterator li;
for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) {
s.insert (*li);
}
}
-AutomationList&
-Automatable::automation_list (uint32_t parameter)
+
+/** Returns NULL if we don't have an AutomationList for \a parameter.
+ */
+AutomationList*
+Automatable::automation_list (ParamID parameter, bool create_if_missing)
{
- AutomationList* al = _parameter_automation[parameter];
+ std::map<ParamID,AutomationList*>::iterator i = _parameter_automation.find(parameter);
+
+ if (i != _parameter_automation.end()) {
+ return i->second;
+
+ } else if (create_if_missing) {
+ AutomationList* al = new AutomationList (parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter));
+ add_automation_parameter(al);
+ return al;
- if (al == 0) {
- al = _parameter_automation[parameter] = new AutomationList (default_parameter_value (parameter));
- /* let derived classes do whatever they need with this */
- automation_list_creation_callback (parameter, *al);
+ } else {
+ warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
+ return NULL;
}
+}
- return *al;
+const AutomationList*
+Automatable::automation_list (ParamID parameter) const
+{
+ std::map<ParamID,AutomationList*>::const_iterator i = _parameter_automation.find(parameter);
+
+ if (i != _parameter_automation.end()) {
+ return i->second;
+ } else {
+ warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg;
+ return NULL;
+ }
}
+
string
-Automatable::describe_parameter (uint32_t which)
+Automatable::describe_parameter (ParamID param)
{
- /* derived classes will override this */
- return "";
+ /* derived classes like PluginInsert should override this */
+
+ if (param == ParamID(GainAutomation))
+ return _("Fader");
+ else if (param == ParamID(PanAutomation))
+ return _("Pan");
+ else if (param.type() == MidiCCAutomation)
+ return string_compose("MIDI CC %1", param.id());
+ else
+ return param.to_string();
}
void
-Automatable::can_automate (uint32_t what)
+Automatable::can_automate (ParamID what)
{
_can_automate_list.insert (what);
}
void
-Automatable::mark_automation_visible (uint32_t what, bool yn)
+Automatable::mark_automation_visible (ParamID what, bool yn)
{
if (yn) {
_visible_parameter_automation.insert (what);
} else {
- set<uint32_t>::iterator i;
+ set<ParamID>::iterator i;
if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) {
_visible_parameter_automation.erase (i);
@@ -179,7 +225,7 @@ Automatable::mark_automation_visible (uint32_t what, bool yn)
bool
Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
{
- map<uint32_t,AutomationList*>::const_iterator li;
+ map<ParamID,AutomationList*>::const_iterator li;
AutomationList::TimeComparator cmp;
next_event.when = max_frames;
@@ -207,36 +253,50 @@ Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_e
return next_event.when != max_frames;
}
+/** \a legacy_param is used for loading legacy sessions where an object (IO, Panner)
+ * had a single automation parameter, with it's type implicit. Derived objects should
+ * pass that type and it will be used for the untyped AutomationList found.
+ */
int
-Automatable::set_automation_state (const XMLNode& node)
+Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param)
{
Glib::Mutex::Lock lm (_automation_lock);
_parameter_automation.clear ();
+ _visible_parameter_automation.clear ();
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
-
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
- uint32_t param;
- if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
- error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
- continue;
- }
+ /*if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
+ error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
+ continue;
+ }*/
+
+ if ((*niter)->name() == "AutomationList") {
+
+ const XMLProperty* id_prop = (*niter)->property("automation-id");
- AutomationList& al = automation_list (param);
- if (al.set_state (*(*niter)->children().front())) {
- goto bad;
+ ParamID param = (id_prop ? ParamID(id_prop->value()) : legacy_param);
+
+ AutomationList* al = new AutomationList(**niter, param);
+
+ if (!id_prop) {
+ warning << "AutomationList node without automation-id property, "
+ << "using default: " << legacy_param.to_string() << endmsg;
+ al->set_param_id(legacy_param);
+ }
+
+ add_automation_parameter(al);
+
+ } else {
+ error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg;
}
}
return 0;
-
- bad:
- error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
- _parameter_automation.clear ();
- return -1;
}
XMLNode&
@@ -244,24 +304,108 @@ Automatable::get_automation_state ()
{
Glib::Mutex::Lock lm (_automation_lock);
XMLNode* node = new XMLNode (X_("Automation"));
- string fullpath;
+
+ cerr << "'" << _name << "'->get_automation_state, # params = " << _parameter_automation.size() << endl;
if (_parameter_automation.empty()) {
return *node;
}
- map<uint32_t,AutomationList*>::iterator li;
+ map<ParamID,AutomationList*>::iterator li;
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
-
- XMLNode* child;
-
- char buf[64];
- stringstream str;
- snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
- child = new XMLNode (buf);
- child->add_child_nocopy (li->second->get_state ());
+ node->add_child_nocopy (li->second->get_state ());
}
return *node;
}
+
+void
+Automatable::clear_automation ()
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+
+ map<ParamID,AutomationList*>::iterator li;
+
+ for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li)
+ li->second->clear();
+}
+
+void
+Automatable::set_parameter_automation_state (ParamID param, AutoState s)
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+
+ AutomationList* al = automation_list (param, true);
+
+ if (s != al->automation_state()) {
+ al->set_automation_state (s);
+ _session.set_dirty ();
+ }
+}
+
+AutoState
+Automatable::get_parameter_automation_state (ParamID param)
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+
+ AutomationList* al = automation_list(param);
+
+ if (al) {
+ return al->automation_state();
+ } else {
+ return Off;
+ }
+}
+
+void
+Automatable::set_parameter_automation_style (ParamID param, AutoStyle s)
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+
+ AutomationList* al = automation_list (param, true);
+
+ if (s != al->automation_style()) {
+ al->set_automation_style (s);
+ _session.set_dirty ();
+ }
+}
+
+AutoStyle
+Automatable::get_parameter_automation_style (ParamID param)
+{
+ Glib::Mutex::Lock lm (_automation_lock);
+
+ AutomationList* al = automation_list(param);
+
+ if (al) {
+ return al->automation_style();
+ } else {
+ return Absolute; // whatever
+ }
+}
+
+void
+Automatable::protect_automation ()
+{
+ set<ParamID> automated_params;
+
+ what_has_automation (automated_params);
+
+ for (set<ParamID>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
+
+ AutomationList* al = automation_list (*i);
+
+ switch (al->automation_state()) {
+ case Write:
+ al->set_automation_state (Off);
+ break;
+ case Touch:
+ al->set_automation_state (Play);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index 50688dda2c..82d3e457cb 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -24,7 +24,9 @@
#include <sstream>
#include <algorithm>
#include <sigc++/bind.h>
+#include <ardour/param_id.h>
#include <ardour/automation_event.h>
+#include <ardour/curve.h>
#include <pbd/stacktrace.h>
#include "i18n.h"
@@ -52,70 +54,72 @@ static void dumpit (const AutomationList& al, string prefix = "")
}
#endif
-AutomationList::AutomationList (double defval)
+AutomationList::AutomationList (ParamID id, double min_val, double max_val, double default_val)
+ : _param_id(id)
+ , _curve(new Curve(*this))
{
+ _param_id = id;
_frozen = 0;
- changed_when_thawed = false;
+ _changed_when_thawed = false;
_state = Off;
_style = Absolute;
+ _min_yval = min_val;
+ _max_yval = max_val;
_touching = false;
- min_yval = FLT_MIN;
- max_yval = FLT_MAX;
- max_xval = 0; // means "no limit"
- default_value = defval;
- _dirty = false;
- rt_insertion_point = events.end();
- lookup_cache.left = -1;
- lookup_cache.range.first = events.end();
- sort_pending = false;
-
- AutomationListCreated(this);
+ _max_xval = 0; // means "no limit"
+ _default_value = default_val;
+ _rt_insertion_point = _events.end();
+ _lookup_cache.left = -1;
+ _lookup_cache.range.first = _events.end();
+ _sort_pending = false;
+
+
+ AutomationListCreated(this);
}
AutomationList::AutomationList (const AutomationList& other)
+ : _param_id(other._param_id)
+ , _curve(new Curve(*this))
{
_frozen = 0;
- changed_when_thawed = false;
+ _changed_when_thawed = false;
_style = other._style;
- min_yval = other.min_yval;
- max_yval = other.max_yval;
- max_xval = other.max_xval;
- default_value = other.default_value;
+ _min_yval = other._min_yval;
+ _max_yval = other._max_yval;
+ _max_xval = other._max_xval;
+ _default_value = other._default_value;
_state = other._state;
_touching = other._touching;
- _dirty = false;
- rt_insertion_point = events.end();
- lookup_cache.left = -1;
- lookup_cache.range.first = events.end();
- sort_pending = false;
-
- for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
- /* we have to use other point_factory() because
- its virtual and we're in a constructor.
- */
- events.push_back (other.point_factory (**i));
+ _rt_insertion_point = _events.end();
+ _lookup_cache.left = -1;
+ _lookup_cache.range.first = _events.end();
+ _sort_pending = false;
+
+ for (const_iterator i = other._events.begin(); i != other._events.end(); ++i) {
+ _events.push_back (new ControlEvent (**i));
}
mark_dirty ();
- AutomationListCreated(this);
+ AutomationListCreated(this);
}
AutomationList::AutomationList (const AutomationList& other, double start, double end)
+ : _param_id(other._param_id)
+ , _curve(new Curve(*this))
{
_frozen = 0;
- changed_when_thawed = false;
+ _changed_when_thawed = false;
_style = other._style;
- min_yval = other.min_yval;
- max_yval = other.max_yval;
- max_xval = other.max_xval;
- default_value = other.default_value;
+ _min_yval = other._min_yval;
+ _max_yval = other._max_yval;
+ _max_xval = other._max_xval;
+ _default_value = other._default_value;
_state = other._state;
_touching = other._touching;
- _dirty = false;
- rt_insertion_point = events.end();
- lookup_cache.left = -1;
- lookup_cache.range.first = events.end();
- sort_pending = false;
+ _rt_insertion_point = _events.end();
+ _lookup_cache.left = -1;
+ _lookup_cache.range.first = _events.end();
+ _sort_pending = false;
/* now grab the relevant points, and shift them back if necessary */
@@ -123,7 +127,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
if (!section->empty()) {
for (AutomationList::iterator i = section->begin(); i != section->end(); ++i) {
- events.push_back (other.point_factory ((*i)->when, (*i)->value));
+ _events.push_back (new ControlEvent ((*i)->when, (*i)->value));
}
}
@@ -134,32 +138,38 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
AutomationListCreated(this);
}
-AutomationList::AutomationList (const XMLNode& node)
+/** \a id is used for legacy sessions where the type is not present
+ * in or below the <AutomationList> node. It is used if \a id is non-null.
+ */
+AutomationList::AutomationList (const XMLNode& node, ParamID id)
+ : _curve(new Curve(*this))
{
_frozen = 0;
- changed_when_thawed = false;
+ _changed_when_thawed = false;
_touching = false;
- min_yval = FLT_MIN;
- max_yval = FLT_MAX;
- max_xval = 0; // means "no limit"
- _dirty = false;
+ _min_yval = FLT_MIN;
+ _max_yval = FLT_MAX;
+ _max_xval = 0; // means "no limit"
_state = Off;
_style = Absolute;
- rt_insertion_point = events.end();
- lookup_cache.left = -1;
- lookup_cache.range.first = events.end();
- sort_pending = false;
+ _rt_insertion_point = _events.end();
+ _lookup_cache.left = -1;
+ _lookup_cache.range.first = _events.end();
+ _sort_pending = false;
set_state (node);
- AutomationListCreated(this);
+ if (id)
+ _param_id = id;
+
+ AutomationListCreated(this);
}
AutomationList::~AutomationList()
{
GoingAway ();
- for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
+ for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
delete (*x);
}
}
@@ -167,7 +177,7 @@ AutomationList::~AutomationList()
bool
AutomationList::operator== (const AutomationList& other)
{
- return events == other.events;
+ return _events == other._events;
}
AutomationList&
@@ -175,16 +185,16 @@ AutomationList::operator= (const AutomationList& other)
{
if (this != &other) {
- events.clear ();
+ _events.clear ();
- for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
- events.push_back (point_factory (**i));
+ for (const_iterator i = other._events.begin(); i != other._events.end(); ++i) {
+ _events.push_back (new ControlEvent (**i));
}
- min_yval = other.min_yval;
- max_yval = other.max_yval;
- max_xval = other.max_xval;
- default_value = other.default_value;
+ _min_yval = other._min_yval;
+ _max_yval = other._max_yval;
+ _max_xval = other._max_xval;
+ _default_value = other._default_value;
mark_dirty ();
maybe_signal_changed ();
@@ -199,7 +209,7 @@ AutomationList::maybe_signal_changed ()
mark_dirty ();
if (_frozen) {
- changed_when_thawed = true;
+ _changed_when_thawed = true;
} else {
StateChanged ();
}
@@ -241,8 +251,8 @@ void
AutomationList::clear ()
{
{
- Glib::Mutex::Lock lm (lock);
- events.clear ();
+ Glib::Mutex::Lock lm (_lock);
+ _events.clear ();
mark_dirty ();
}
@@ -252,25 +262,25 @@ AutomationList::clear ()
void
AutomationList::x_scale (double factor)
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
_x_scale (factor);
}
bool
AutomationList::extend_to (double when)
{
- Glib::Mutex::Lock lm (lock);
- if (events.empty() || events.back()->when == when) {
+ Glib::Mutex::Lock lm (_lock);
+ if (_events.empty() || _events.back()->when == when) {
return false;
}
- double factor = when / events.back()->when;
+ double factor = when / _events.back()->when;
_x_scale (factor);
return true;
}
void AutomationList::_x_scale (double factor)
{
- for (AutomationList::iterator i = events.begin(); i != events.end(); ++i) {
+ for (AutomationList::iterator i = _events.begin(); i != _events.end(); ++i) {
(*i)->when = floor ((*i)->when * factor);
}
@@ -280,11 +290,9 @@ void AutomationList::_x_scale (double factor)
void
AutomationList::reposition_for_rt_add (double when)
{
- rt_insertion_point = events.end();
+ _rt_insertion_point = _events.end();
}
-#define last_rt_insertion_point rt_insertion_point
-
void
AutomationList::rt_add (double when, double value)
{
@@ -297,26 +305,26 @@ AutomationList::rt_add (double when, double value)
// cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
iterator where;
TimeComparator cmp;
ControlEvent cp (when, 0.0);
bool done = false;
- if ((last_rt_insertion_point != events.end()) && ((*last_rt_insertion_point)->when < when) ) {
+ 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 = last_rt_insertion_point;
+ iterator after = _rt_insertion_point;
- if (++after != events.end()) {
+ if (++after != _events.end()) {
iterator far = after;
- while (far != events.end()) {
+ while (far != _events.end()) {
if ((*far)->when > when) {
break;
}
@@ -325,14 +333,14 @@ AutomationList::rt_add (double when, double value)
if(_new_touch) {
where = far;
- last_rt_insertion_point = where;
+ _rt_insertion_point = where;
if((*where)->when == when) {
(*where)->value = value;
done = true;
}
} else {
- where = events.erase (after, far);
+ where = _events.erase (after, far);
}
} else {
@@ -341,20 +349,20 @@ AutomationList::rt_add (double when, double value)
}
- iterator previous = last_rt_insertion_point;
- --previous;
+ iterator previous = _rt_insertion_point;
+ --previous;
- if (last_rt_insertion_point != events.begin() && (*last_rt_insertion_point)->value == value && (*previous)->value == value) {
- (*last_rt_insertion_point)->when = when;
+ 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, cmp);
+ where = lower_bound (_events.begin(), _events.end(), &cp, cmp);
- if (where != events.end()) {
+ if (where != _events.end()) {
if ((*where)->when == when) {
(*where)->value = value;
done = true;
@@ -363,7 +371,7 @@ AutomationList::rt_add (double when, double value)
}
if (!done) {
- last_rt_insertion_point = events.insert (where, point_factory (when, value));
+ _rt_insertion_point = _events.insert (where, new ControlEvent (when, value));
}
_new_touch = false;
@@ -377,24 +385,22 @@ void
AutomationList::fast_simple_add (double when, double value)
{
/* to be used only for loading pre-sorted data from saved state */
- events.insert (events.end(), point_factory (when, value));
+ _events.insert (_events.end(), new ControlEvent (when, value));
}
-#undef last_rt_insertion_point
-
void
AutomationList::add (double when, double value)
{
/* this is for graphical editing */
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
TimeComparator cmp;
ControlEvent cp (when, 0.0f);
bool insert = true;
iterator insertion_point;
- for (insertion_point = lower_bound (events.begin(), events.end(), &cp, cmp); insertion_point != events.end(); ++insertion_point) {
+ for (insertion_point = lower_bound (_events.begin(), _events.end(), &cp, cmp); insertion_point != _events.end(); ++insertion_point) {
/* only one point allowed per time point */
@@ -411,7 +417,7 @@ AutomationList::add (double when, double value)
if (insert) {
- events.insert (insertion_point, point_factory (when, value));
+ _events.insert (insertion_point, new ControlEvent (when, value));
reposition_for_rt_add (0);
}
@@ -426,8 +432,8 @@ void
AutomationList::erase (AutomationList::iterator i)
{
{
- Glib::Mutex::Lock lm (lock);
- events.erase (i);
+ Glib::Mutex::Lock lm (_lock);
+ _events.erase (i);
reposition_for_rt_add (0);
mark_dirty ();
}
@@ -438,8 +444,8 @@ void
AutomationList::erase (AutomationList::iterator start, AutomationList::iterator end)
{
{
- Glib::Mutex::Lock lm (lock);
- events.erase (start, end);
+ Glib::Mutex::Lock lm (_lock);
+ _events.erase (start, end);
reposition_for_rt_add (0);
mark_dirty ();
}
@@ -452,19 +458,19 @@ AutomationList::reset_range (double start, double endt)
bool reset = false;
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
TimeComparator cmp;
ControlEvent cp (start, 0.0f);
iterator s;
iterator e;
- if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
+ if ((s = lower_bound (_events.begin(), _events.end(), &cp, cmp)) != _events.end()) {
cp.when = endt;
- e = upper_bound (events.begin(), events.end(), &cp, cmp);
+ e = upper_bound (_events.begin(), _events.end(), &cp, cmp);
for (iterator i = s; i != e; ++i) {
- (*i)->value = default_value;
+ (*i)->value = _default_value;
}
reset = true;
@@ -484,16 +490,16 @@ AutomationList::erase_range (double start, double endt)
bool erased = false;
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
TimeComparator cmp;
ControlEvent cp (start, 0.0f);
iterator s;
iterator e;
- if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
+ if ((s = lower_bound (_events.begin(), _events.end(), &cp, cmp)) != _events.end()) {
cp.when = endt;
- e = upper_bound (events.begin(), events.end(), &cp, cmp);
- events.erase (s, e);
+ e = upper_bound (_events.begin(), _events.end(), &cp, cmp);
+ _events.erase (s, e);
reposition_for_rt_add (0);
erased = true;
mark_dirty ();
@@ -515,7 +521,7 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double
*/
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
while (start != end) {
(*start)->when += xdelta;
@@ -527,9 +533,9 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double
}
if (!_frozen) {
- events.sort (sort_events_by_time);
+ _events.sort (sort_events_by_time);
} else {
- sort_pending = true;
+ _sort_pending = true;
}
mark_dirty ();
@@ -542,13 +548,13 @@ void
AutomationList::slide (iterator before, double distance)
{
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
- if (before == events.end()) {
+ if (before == _events.end()) {
return;
}
- while (before != events.end()) {
+ while (before != _events.end()) {
(*before)->when += distance;
++before;
}
@@ -566,7 +572,7 @@ AutomationList::modify (iterator iter, double when, double val)
*/
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
(*iter)->when = when;
(*iter)->value = val;
@@ -576,9 +582,9 @@ AutomationList::modify (iterator iter, double when, double val)
}
if (!_frozen) {
- events.sort (sort_events_by_time);
+ _events.sort (sort_events_by_time);
} else {
- sort_pending = true;
+ _sort_pending = true;
}
mark_dirty ();
@@ -590,20 +596,20 @@ AutomationList::modify (iterator iter, double when, double val)
std::pair<AutomationList::iterator,AutomationList::iterator>
AutomationList::control_points_adjacent (double xval)
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
iterator i;
TimeComparator cmp;
ControlEvent cp (xval, 0.0f);
std::pair<iterator,iterator> ret;
- ret.first = events.end();
- ret.second = events.end();
+ ret.first = _events.end();
+ ret.second = _events.end();
- for (i = lower_bound (events.begin(), events.end(), &cp, cmp); i != events.end(); ++i) {
+ for (i = lower_bound (_events.begin(), _events.end(), &cp, cmp); i != _events.end(); ++i) {
- if (ret.first == events.end()) {
+ if (ret.first == _events.end()) {
if ((*i)->when >= xval) {
- if (i != events.begin()) {
+ if (i != _events.begin()) {
ret.first = i;
--ret.first;
} else {
@@ -641,15 +647,15 @@ AutomationList::thaw ()
}
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
- if (sort_pending) {
- events.sort (sort_events_by_time);
- sort_pending = false;
+ if (_sort_pending) {
+ _events.sort (sort_events_by_time);
+ _sort_pending = false;
}
}
- if (changed_when_thawed) {
+ if (_changed_when_thawed) {
StateChanged(); /* EMIT SIGNAL */
}
}
@@ -657,44 +663,44 @@ AutomationList::thaw ()
void
AutomationList::set_max_xval (double x)
{
- max_xval = x;
+ _max_xval = x;
}
void
AutomationList::mark_dirty ()
{
- lookup_cache.left = -1;
- _dirty = true;
+ _lookup_cache.left = -1;
+ Dirty (); /* EMIT SIGNAL */
}
void
AutomationList::truncate_end (double last_coordinate)
{
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
ControlEvent cp (last_coordinate, 0);
list<ControlEvent*>::reverse_iterator i;
double last_val;
- if (events.empty()) {
+ if (_events.empty()) {
return;
}
- if (last_coordinate == events.back()->when) {
+ if (last_coordinate == _events.back()->when) {
return;
}
- if (last_coordinate > events.back()->when) {
+ if (last_coordinate > _events.back()->when) {
/* extending end:
*/
- iterator foo = events.begin();
+ iterator foo = _events.begin();
bool lessthantwo;
- if (foo == events.end()) {
+ if (foo == _events.end()) {
lessthantwo = true;
- } else if (++foo == events.end()) {
+ } else if (++foo == _events.end()) {
lessthantwo = true;
} else {
lessthantwo = false;
@@ -702,7 +708,7 @@ AutomationList::truncate_end (double last_coordinate)
if (lessthantwo) {
/* less than 2 points: add a new point */
- events.push_back (point_factory (last_coordinate, events.back()->value));
+ _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
} else {
/* more than 2 points: check to see if the last 2 values
@@ -710,14 +716,14 @@ AutomationList::truncate_end (double last_coordinate)
last point. otherwise, add a new point.
*/
- iterator penultimate = events.end();
+ iterator penultimate = _events.end();
--penultimate; /* points at last point */
--penultimate; /* points at the penultimate point */
- if (events.back()->value == (*penultimate)->value) {
- events.back()->when = last_coordinate;
+ if (_events.back()->value == (*penultimate)->value) {
+ _events.back()->when = last_coordinate;
} else {
- events.push_back (point_factory (last_coordinate, events.back()->value));
+ _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
}
}
@@ -726,10 +732,10 @@ AutomationList::truncate_end (double last_coordinate)
/* shortening end */
last_val = unlocked_eval (last_coordinate);
- last_val = max ((double) min_yval, last_val);
- last_val = min ((double) max_yval, last_val);
+ last_val = max ((double) _min_yval, last_val);
+ last_val = min ((double) _max_yval, last_val);
- i = events.rbegin();
+ i = _events.rbegin();
/* make i point to the last control point */
@@ -739,9 +745,9 @@ AutomationList::truncate_end (double last_coordinate)
beyond the new last coordinate.
*/
- uint32_t sz = events.size();
+ uint32_t sz = _events.size();
- while (i != events.rend() && sz > 2) {
+ while (i != _events.rend() && sz > 2) {
list<ControlEvent*>::reverse_iterator tmp;
tmp = i;
@@ -751,14 +757,14 @@ AutomationList::truncate_end (double last_coordinate)
break;
}
- events.erase (i.base());
+ _events.erase (i.base());
--sz;
i = tmp;
}
- events.back()->when = last_coordinate;
- events.back()->value = last_val;
+ _events.back()->when = last_coordinate;
+ _events.back()->value = last_val;
}
reposition_for_rt_add (0);
@@ -772,12 +778,12 @@ void
AutomationList::truncate_start (double overall_length)
{
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
AutomationList::iterator i;
double first_legal_value;
double first_legal_coordinate;
- if (events.empty()) {
+ if (_events.empty()) {
fatal << _("programming error:")
<< "AutomationList::truncate_start() called on an empty list"
<< endmsg;
@@ -785,26 +791,26 @@ AutomationList::truncate_start (double overall_length)
return;
}
- if (overall_length == events.back()->when) {
+ if (overall_length == _events.back()->when) {
/* no change in overall length */
return;
}
- if (overall_length > events.back()->when) {
+ if (overall_length > _events.back()->when) {
/* growing at front: duplicate first point. shift all others */
- double shift = overall_length - events.back()->when;
+ double shift = overall_length - _events.back()->when;
uint32_t np;
- for (np = 0, i = events.begin(); i != events.end(); ++i, ++np) {
+ for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
(*i)->when += shift;
}
if (np < 2) {
/* less than 2 points: add a new point */
- events.push_front (point_factory (0, events.front()->value));
+ _events.push_front (new ControlEvent (0, _events.front()->value));
} else {
@@ -813,15 +819,15 @@ AutomationList::truncate_start (double overall_length)
first point. otherwise, add a new point.
*/
- iterator second = events.begin();
+ iterator second = _events.begin();
++second; /* points at the second point */
- if (events.front()->value == (*second)->value) {
+ if (_events.front()->value == (*second)->value) {
/* first segment is flat, just move start point back to zero */
- events.front()->when = 0;
+ _events.front()->when = 0;
} else {
/* leave non-flat segment in place, add a new leading point. */
- events.push_front (point_factory (0, events.front()->value));
+ _events.push_front (new ControlEvent (0, _events.front()->value));
}
}
@@ -829,16 +835,16 @@ AutomationList::truncate_start (double overall_length)
/* shrinking at front */
- first_legal_coordinate = events.back()->when - overall_length;
+ first_legal_coordinate = _events.back()->when - overall_length;
first_legal_value = unlocked_eval (first_legal_coordinate);
- first_legal_value = max (min_yval, first_legal_value);
- first_legal_value = min (max_yval, first_legal_value);
+ first_legal_value = max (_min_yval, first_legal_value);
+ first_legal_value = min (_max_yval, first_legal_value);
/* remove all events earlier than the new "front" */
- i = events.begin();
+ i = _events.begin();
- while (i != events.end() && !events.empty()) {
+ while (i != _events.end() && !_events.empty()) {
list<ControlEvent*>::iterator tmp;
tmp = i;
@@ -848,7 +854,7 @@ AutomationList::truncate_start (double overall_length)
break;
}
- events.erase (i);
+ _events.erase (i);
i = tmp;
}
@@ -858,13 +864,13 @@ AutomationList::truncate_start (double overall_length)
relative position
*/
- for (i = events.begin(); i != events.end(); ++i) {
+ for (i = _events.begin(); i != _events.end(); ++i) {
(*i)->when -= first_legal_coordinate;
}
/* add a new point for the interpolated new value */
- events.push_front (point_factory (0, first_legal_value));
+ _events.push_front (new ControlEvent (0, first_legal_value));
}
reposition_for_rt_add (0);
@@ -876,48 +882,42 @@ AutomationList::truncate_start (double overall_length)
}
double
-AutomationList::unlocked_eval (double x)
-{
- return shared_eval (x);
-}
-
-double
-AutomationList::shared_eval (double x)
+AutomationList::unlocked_eval (double x) const
{
- pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
+ pair<EventList::iterator,EventList::iterator> range;
int32_t npoints;
double lpos, upos;
double lval, uval;
double fraction;
- npoints = events.size();
+ npoints = _events.size();
switch (npoints) {
case 0:
- return default_value;
+ return _default_value;
case 1:
- if (x >= events.front()->when) {
- return events.front()->value;
+ if (x >= _events.front()->when) {
+ return _events.front()->value;
} else {
- // return default_value;
- return events.front()->value;
+ // return _default_value;
+ return _events.front()->value;
}
case 2:
- if (x >= events.back()->when) {
- return events.back()->value;
- } else if (x == events.front()->when) {
- return events.front()->value;
- } else if (x < events.front()->when) {
- // return default_value;
- return events.front()->value;
+ if (x >= _events.back()->when) {
+ return _events.back()->value;
+ } else if (x == _events.front()->when) {
+ return _events.front()->value;
+ } else if (x < _events.front()->when) {
+ // return _default_value;
+ return _events.front()->value;
}
- lpos = events.front()->when;
- lval = events.front()->value;
- upos = events.back()->when;
- uval = events.back()->value;
+ lpos = _events.front()->when;
+ lval = _events.front()->value;
+ upos = _events.back()->when;
+ uval = _events.back()->value;
/* linear interpolation betweeen the two points
*/
@@ -927,13 +927,13 @@ AutomationList::shared_eval (double x)
default:
- if (x >= events.back()->when) {
- return events.back()->value;
- } else if (x == events.front()->when) {
- return events.front()->value;
- } else if (x < events.front()->when) {
- // return default_value;
- return events.front()->value;
+ if (x >= _events.back()->when) {
+ return _events.back()->value;
+ } else if (x == _events.front()->when) {
+ return _events.front()->value;
+ } else if (x < _events.front()->when) {
+ // return _default_value;
+ return _events.front()->value;
}
return multipoint_eval (x);
@@ -942,9 +942,9 @@ AutomationList::shared_eval (double x)
}
double
-AutomationList::multipoint_eval (double x)
+AutomationList::multipoint_eval (double x) const
{
- pair<AutomationList::iterator,AutomationList::iterator> range;
+ pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
double upos, lpos;
double uval, lval;
double fraction;
@@ -953,38 +953,38 @@ AutomationList::multipoint_eval (double x)
this was called (or if the lookup cache has been marked "dirty" (left<0)
*/
- if ((lookup_cache.left < 0) ||
- ((lookup_cache.left > x) ||
- (lookup_cache.range.first == events.end()) ||
- ((*lookup_cache.range.second)->when < x))) {
+ if ((_lookup_cache.left < 0) ||
+ ((_lookup_cache.left > x) ||
+ (_lookup_cache.range.first == _events.end()) ||
+ ((*_lookup_cache.range.second)->when < x))) {
ControlEvent cp (x, 0);
TimeComparator cmp;
- lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
+ _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, cmp);
}
- range = lookup_cache.range;
+ range = _lookup_cache.range;
if (range.first == range.second) {
/* x does not exist within the list as a control point */
- lookup_cache.left = x;
+ _lookup_cache.left = x;
- if (range.first != events.begin()) {
+ if (range.first != _events.begin()) {
--range.first;
lpos = (*range.first)->when;
lval = (*range.first)->value;
} else {
/* we're before the first point */
- // return default_value;
- return events.front()->value;
+ // return _default_value;
+ return _events.front()->value;
}
- if (range.second == events.end()) {
+ if (range.second == _events.end()) {
/* we're after the last point */
- return events.back()->value;
+ return _events.back()->value;
}
upos = (*range.second)->when;
@@ -1000,17 +1000,17 @@ AutomationList::multipoint_eval (double x)
}
/* x is a control point in the data */
- lookup_cache.left = -1;
+ _lookup_cache.left = -1;
return (*range.first)->value;
}
AutomationList*
AutomationList::cut (iterator start, iterator end)
{
- AutomationList* nal = new AutomationList (default_value);
+ AutomationList* nal = new AutomationList (_param_id, _min_yval, _max_yval, _default_value);
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
for (iterator x = start; x != end; ) {
iterator tmp;
@@ -1018,8 +1018,8 @@ AutomationList::cut (iterator start, iterator end)
tmp = x;
++tmp;
- nal->events.push_back (point_factory (**x));
- events.erase (x);
+ nal->_events.push_back (new ControlEvent (**x));
+ _events.erase (x);
reposition_for_rt_add (0);
@@ -1037,24 +1037,24 @@ AutomationList::cut (iterator start, iterator end)
AutomationList*
AutomationList::cut_copy_clear (double start, double end, int op)
{
- AutomationList* nal = new AutomationList (default_value);
+ AutomationList* nal = new AutomationList (_param_id, _min_yval, _max_yval, _default_value);
iterator s, e;
ControlEvent cp (start, 0.0);
TimeComparator cmp;
bool changed = false;
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
- if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) == events.end()) {
+ if ((s = lower_bound (_events.begin(), _events.end(), &cp, cmp)) == _events.end()) {
return nal;
}
cp.when = end;
- e = upper_bound (events.begin(), events.end(), &cp, cmp);
+ e = upper_bound (_events.begin(), _events.end(), &cp, cmp);
if (op != 2 && (*s)->when != start) {
- nal->events.push_back (point_factory (0, unlocked_eval (start)));
+ nal->_events.push_back (new ControlEvent (0, unlocked_eval (start)));
}
for (iterator x = s; x != e; ) {
@@ -1070,18 +1070,18 @@ AutomationList::cut_copy_clear (double start, double end, int op)
*/
if (op != 2) {
- nal->events.push_back (point_factory ((*x)->when - start, (*x)->value));
+ nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
}
if (op != 1) {
- events.erase (x);
+ _events.erase (x);
}
x = tmp;
}
- if (op != 2 && nal->events.back()->when != end - start) {
- nal->events.push_back (point_factory (end - start, unlocked_eval (end)));
+ if (op != 2 && nal->_events.back()->when != end - start) {
+ nal->_events.push_back (new ControlEvent (end - start, unlocked_eval (end)));
}
if (changed) {
@@ -1100,10 +1100,10 @@ AutomationList::cut_copy_clear (double start, double end, int op)
AutomationList*
AutomationList::copy (iterator start, iterator end)
{
- AutomationList* nal = new AutomationList (default_value);
+ AutomationList* nal = new AutomationList (_param_id, _min_yval, _max_yval, _default_value);
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
for (iterator x = start; x != end; ) {
iterator tmp;
@@ -1111,7 +1111,7 @@ AutomationList::copy (iterator start, iterator end)
tmp = x;
++tmp;
- nal->events.push_back (point_factory (**x));
+ nal->_events.push_back (new ControlEvent (**x));
x = tmp;
}
@@ -1141,22 +1141,22 @@ AutomationList::clear (double start, double end)
bool
AutomationList::paste (AutomationList& alist, double pos, float times)
{
- if (alist.events.empty()) {
+ if (alist._events.empty()) {
return false;
}
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
iterator where;
iterator prev;
double end = 0;
ControlEvent cp (pos, 0.0);
TimeComparator cmp;
- where = upper_bound (events.begin(), events.end(), &cp, cmp);
+ where = upper_bound (_events.begin(), _events.end(), &cp, cmp);
for (iterator i = alist.begin();i != alist.end(); ++i) {
- events.insert (where, point_factory( (*i)->when+pos,( *i)->value));
+ _events.insert (where, new ControlEvent( (*i)->when+pos,( *i)->value));
end = (*i)->when + pos;
}
@@ -1165,12 +1165,12 @@ AutomationList::paste (AutomationList& alist, double pos, float times)
the correct amount.
*/
- while (where != events.end()) {
+ while (where != _events.end()) {
iterator tmp;
if ((*where)->when <= end) {
tmp = where;
++tmp;
- events.erase(where);
+ _events.erase(where);
where = tmp;
} else {
@@ -1186,18 +1186,6 @@ AutomationList::paste (AutomationList& alist, double pos, float times)
return true;
}
-ControlEvent*
-AutomationList::point_factory (double when, double val) const
-{
- return new ControlEvent (when, val);
-}
-
-ControlEvent*
-AutomationList::point_factory (const ControlEvent& other) const
-{
- return new ControlEvent (other);
-}
-
XMLNode&
AutomationList::get_state ()
{
@@ -1207,20 +1195,24 @@ AutomationList::get_state ()
XMLNode&
AutomationList::state (bool full)
{
+ cerr << _param_id.to_string() << "->state()" << endl;
+
XMLNode* root = new XMLNode (X_("AutomationList"));
char buf[64];
LocaleGuard lg (X_("POSIX"));
+ root->add_property ("automation-id", _param_id.to_string());
+
root->add_property ("id", _id.to_s());
- snprintf (buf, sizeof (buf), "%.12g", default_value);
+ snprintf (buf, sizeof (buf), "%.12g", _default_value);
root->add_property ("default", buf);
- snprintf (buf, sizeof (buf), "%.12g", min_yval);
- root->add_property ("min_yval", buf);
- snprintf (buf, sizeof (buf), "%.12g", max_yval);
- root->add_property ("max_yval", buf);
- snprintf (buf, sizeof (buf), "%.12g", max_xval);
- root->add_property ("max_xval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", _min_yval);
+ root->add_property ("_min_yval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", _max_yval);
+ root->add_property ("_max_yval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", _max_xval);
+ root->add_property ("_max_xval", buf);
if (full) {
root->add_property ("state", auto_state_to_string (_state));
@@ -1231,7 +1223,7 @@ AutomationList::state (bool full)
root->add_property ("style", auto_style_to_string (_style));
- if (!events.empty()) {
+ if (!_events.empty()) {
root->add_child_nocopy (serialize_events());
}
@@ -1244,7 +1236,7 @@ AutomationList::serialize_events ()
XMLNode* node = new XMLNode (X_("events"));
stringstream str;
- for (iterator xx = events.begin(); xx != events.end(); ++xx) {
+ for (iterator xx = _events.begin(); xx != _events.end(); ++xx) {
str << (double) (*xx)->when;
str << ' ';
str <<(double) (*xx)->value;
@@ -1367,17 +1359,25 @@ AutomationList::set_state (const XMLNode& node)
error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
return -1;
}
-
+
if ((prop = node.property ("id")) != 0) {
_id = prop->value ();
/* update session AL list */
AutomationListCreated(this);
}
+ if ((prop = node.property (X_("automation-id"))) != 0){
+ _param_id = ParamID(prop->value());
+ } else {
+ warning << "Legacy session: automation list has no automation-id property.";
+ }
+
+ cerr << "Loaded automation " << _param_id.to_string() << endl;
+
if ((prop = node.property (X_("default"))) != 0){
- default_value = atof (prop->value());
+ _default_value = atof (prop->value());
} else {
- default_value = 0.0;
+ _default_value = 0.0;
}
if ((prop = node.property (X_("style"))) != 0) {
@@ -1392,22 +1392,22 @@ AutomationList::set_state (const XMLNode& node)
_state = Off;
}
- if ((prop = node.property (X_("min_yval"))) != 0) {
- min_yval = atof (prop->value ());
+ if ((prop = node.property (X_("_min_yval"))) != 0) {
+ _min_yval = atof (prop->value ());
} else {
- min_yval = FLT_MIN;
+ _min_yval = FLT_MIN;
}
- if ((prop = node.property (X_("max_yval"))) != 0) {
- max_yval = atof (prop->value ());
+ if ((prop = node.property (X_("_max_yval"))) != 0) {
+ _max_yval = atof (prop->value ());
} else {
- max_yval = FLT_MAX;
+ _max_yval = FLT_MAX;
}
- if ((prop = node.property (X_("max_xval"))) != 0) {
- max_xval = atof (prop->value ());
+ if ((prop = node.property (X_("_max_xval"))) != 0) {
+ _max_xval = atof (prop->value ());
} else {
- max_xval = 0; // means "no limit ;
+ _max_xval = 0; // means "no limit ;
}
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 847741832d..e5770507d5 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -78,8 +78,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
nframes_t position,
AnchorPoint ap)
: AudioRegion (position, length, "foobar"),
- _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
- _fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
+ _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
+ _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
_in = in;
@@ -96,8 +96,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
: AudioRegion (0, 0, "foobar"),
- _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
- _fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
+ _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
+ _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
_in_update = false;
_fixed = false;
@@ -115,8 +115,8 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
: AudioRegion (0, 0, "foobar"),
- _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
- _fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
+ _fade_in (ParamID(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
+ _fade_out (ParamID(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
boost::shared_ptr<Region> r;
@@ -300,8 +300,8 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
float* fiv = new float[to_write];
float* fov = new float[to_write];
- _fade_in.get_vector (offset, offset+to_write, fiv, to_write);
- _fade_out.get_vector (offset, offset+to_write, fov, to_write);
+ _fade_in.curve().get_vector (offset, offset+to_write, fiv, to_write);
+ _fade_out.curve().get_vector (offset, offset+to_write, fov, to_write);
/* note: although we have not explicitly taken into account the return values
from _out->read_at() or _in->read_at(), the length() function does this
diff --git a/libs/ardour/curve.cc b/libs/ardour/curve.cc
index 5a1dc108f8..3aa9de9127 100644
--- a/libs/ardour/curve.cc
+++ b/libs/ardour/curve.cc
@@ -31,6 +31,7 @@
#include <sigc++/bind.h>
#include "ardour/curve.h"
+#include "ardour/automation_event.h"
#include "i18n.h"
@@ -39,31 +40,35 @@ using namespace ARDOUR;
using namespace sigc;
using namespace PBD;
-Curve::Curve (double minv, double maxv, double canv, bool nostate)
- : AutomationList (canv)
+Curve::Curve (const AutomationList& al)
+ : _list (al)
+ , _dirty (true)
{
- min_yval = minv;
- max_yval = maxv;
+ _list.Dirty.connect(mem_fun(*this, &Curve::on_list_dirty));
}
Curve::Curve (const Curve& other)
- : AutomationList (other)
+ : _list (other._list)
+ , _dirty (true)
{
- min_yval = other.min_yval;
- max_yval = other.max_yval;
+ _list.Dirty.connect(mem_fun(*this, &Curve::on_list_dirty));
}
-
+#if 0
Curve::Curve (const Curve& other, double start, double end)
- : AutomationList (other, start, end)
+ : _list (other._list)
{
- min_yval = other.min_yval;
- max_yval = other.max_yval;
+ _min_yval = other._min_yval;
+ _max_yval = other._max_yval;
}
-Curve::Curve (const XMLNode& node)
- : AutomationList (node)
+/** \a id is used for legacy sessions where the type is not present
+ * in or below the <AutomationList> node. It is used if \a id is non-null.
+ */
+Curve::Curve (const XMLNode& node, ParamID id)
+ : AutomationList (node, id)
{
}
+#endif
Curve::~Curve ()
{
@@ -78,7 +83,7 @@ Curve::solve ()
return;
}
- if ((npoints = events.size()) > 2) {
+ if ((npoints = _list.events().size()) > 2) {
/* Compute coefficients needed to efficiently compute a constrained spline
curve. See "Constrained Cubic Spline Interpolation" by CJC Kruger
@@ -88,9 +93,9 @@ Curve::solve ()
double x[npoints];
double y[npoints];
uint32_t i;
- AutomationEventList::iterator xx;
+ AutomationList::EventList::const_iterator xx;
- for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
+ for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
x[i] = (double) (*xx)->when;
y[i] = (double) (*xx)->value;
}
@@ -108,16 +113,7 @@ Curve::solve ()
double fplast = 0;
- for (i = 0, xx = events.begin(); xx != events.end(); ++xx, ++i) {
-
- CurvePoint* cp = dynamic_cast<CurvePoint*>(*xx);
-
- if (cp == 0) {
- fatal << _("programming error: ")
- << X_("non-CurvePoint event found in event list for a Curve")
- << endmsg;
- /*NOTREACHED*/
- }
+ for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
double xdelta; /* gcc is wrong about possible uninitialized use */
double xdelta2; /* ditto */
@@ -192,10 +188,10 @@ Curve::solve ()
/* store */
- cp->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
- cp->coeff[1] = b;
- cp->coeff[2] = c;
- cp->coeff[3] = d;
+ (*xx)->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
+ (*xx)->coeff[1] = b;
+ (*xx)->coeff[2] = c;
+ (*xx)->coeff[3] = d;
fplast = fpi;
}
@@ -208,7 +204,7 @@ Curve::solve ()
bool
Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
- Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock lm(_list.lock(), Glib::TRY_LOCK);
if (!lm.locked()) {
return false;
@@ -221,7 +217,7 @@ Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen)
void
Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm(_list.lock());
_get_vector (x0, x1, vec, veclen);
}
@@ -233,22 +229,22 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
int32_t original_veclen;
int32_t npoints;
- if ((npoints = events.size()) == 0) {
- for (i = 0; i < veclen; ++i) {
- vec[i] = default_value;
- }
- return;
+ if ((npoints = _list.events().size()) == 0) {
+ for (i = 0; i < veclen; ++i) {
+ vec[i] = _list.default_value();
+ }
+ return;
}
/* events is now known not to be empty */
- max_x = events.back()->when;
- min_x = events.front()->when;
+ max_x = _list.events().back()->when;
+ min_x = _list.events().front()->when;
lx = max (min_x, x0);
if (x1 < 0) {
- x1 = events.back()->when;
+ x1 = _list.events().back()->when;
}
hx = min (max_x, x1);
@@ -267,7 +263,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
subveclen = min (subveclen, veclen);
for (i = 0; i < subveclen; ++i) {
- vec[i] = events.front()->value;
+ vec[i] = _list.events().front()->value;
}
veclen -= subveclen;
@@ -286,7 +282,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
subveclen = min (subveclen, veclen);
- val = events.back()->value;
+ val = _list.events().back()->value;
i = veclen - subveclen;
@@ -304,7 +300,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
if (npoints == 1 ) {
for (i = 0; i < veclen; ++i) {
- vec[i] = events.front()->value;
+ vec[i] = _list.events().front()->value;
}
return;
}
@@ -325,11 +321,11 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
dx = 0; // not used
}
- double slope = (events.back()->value - events.front()->value)/
- (events.back()->when - events.front()->when);
+ double slope = (_list.events().back()->value - _list.events().front()->value)/
+ (_list.events().back()->when - _list.events().front()->when);
double yfrac = dx*slope;
- vec[0] = events.front()->value + slope * (lx - events.front()->when);
+ vec[0] = _list.events().front()->value + slope * (lx - _list.events().front()->when);
for (i = 1; i < veclen; ++i) {
vec[i] = vec[i-1] + yfrac;
@@ -357,27 +353,31 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
double
Curve::unlocked_eval (double x)
{
+ // I don't see the point of this...
+
if (_dirty) {
solve ();
}
- return shared_eval (x);
+ return _list.unlocked_eval (x);
}
double
Curve::multipoint_eval (double x)
{
- pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
+ pair<AutomationList::EventList::const_iterator,AutomationList::EventList::const_iterator> range;
+
+ AutomationList::LookupCache& lookup_cache = _list.lookup_cache();
if ((lookup_cache.left < 0) ||
((lookup_cache.left > x) ||
- (lookup_cache.range.first == events.end()) ||
+ (lookup_cache.range.first == _list.events().end()) ||
((*lookup_cache.range.second)->when < x))) {
- TimeComparator cmp;
+ AutomationList::TimeComparator cmp;
ControlEvent cp (x, 0.0);
- lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
+ lookup_cache.range = equal_range (_list.events().begin(), _list.events().end(), &cp, cmp);
}
range = lookup_cache.range;
@@ -399,21 +399,21 @@ Curve::multipoint_eval (double x)
lookup_cache.left = x;
- if (range.first == events.begin()) {
+ if (range.first == _list.events().begin()) {
/* we're before the first point */
// return default_value;
- events.front()->value;
+ _list.events().front()->value;
}
- if (range.second == events.end()) {
+ if (range.second == _list.events().end()) {
/* we're after the last point */
- return events.back()->value;
+ return _list.events().back()->value;
}
double x2 = x * x;
- CurvePoint* cp = dynamic_cast<CurvePoint*> (*range.second);
+ ControlEvent* ev = *range.second;
- return cp->coeff[0] + (cp->coeff[1] * x) + (cp->coeff[2] * x2) + (cp->coeff[3] * x2 * x);
+ return ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x);
}
/* x is a control point in the data */
@@ -422,18 +422,6 @@ Curve::multipoint_eval (double x)
return (*range.first)->value;
}
-ControlEvent*
-Curve::point_factory (double when, double val) const
-{
- return new CurvePoint (when, val);
-}
-
-ControlEvent*
-Curve::point_factory (const ControlEvent& other) const
-{
- return new CurvePoint (other.when, other.value);
-}
-
extern "C" {
void
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index 356c0df5c1..5a65135f75 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -104,6 +104,10 @@ setup_enum_writer ()
REGISTER_ENUM (PluginAutomation);
REGISTER_ENUM (SoloAutomation);
REGISTER_ENUM (MuteAutomation);
+ REGISTER_ENUM (MidiCCAutomation);
+ REGISTER_ENUM (FadeInAutomation);
+ REGISTER_ENUM (FadeOutAutomation);
+ REGISTER_ENUM (EnvelopeAutomation);
REGISTER_BITS (_AutomationType);
REGISTER_ENUM (Off);
diff --git a/libs/ardour/gain.cc b/libs/ardour/gain.cc
index 369df7348c..b067e6c08d 100644
--- a/libs/ardour/gain.cc
+++ b/libs/ardour/gain.cc
@@ -22,12 +22,12 @@
using namespace ARDOUR;
Gain::Gain ()
- : Curve (0.0, 2.0, 1.0f) /* XXX yuck; clamps gain to -inf .. +6db */
+ : AutomationList (ParamID(GainAutomation), 0.0, 2.0, 1.0f) /* XXX yuck; clamps gain to -inf .. +6db */
{
}
Gain::Gain (const Gain& other)
- : Curve (other)
+ : AutomationList (other)
{
}
@@ -35,7 +35,7 @@ Gain&
Gain::operator= (const Gain& other)
{
if (this != &other) {
- Curve::operator= (other);
+ AutomationList::operator= (other);
}
return *this;
}
diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc
index bb02cb0925..1e73c398c2 100644
--- a/libs/ardour/insert.cc
+++ b/libs/ardour/insert.cc
@@ -157,7 +157,7 @@ Insert::state (bool full_state)
XMLNode& automation = Automatable::get_automation_state();
- for (set<uint32_t>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) {
+ for (set<ParamID>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) {
if (x != _visible_parameter_automation.begin()) {
sstr << ' ';
}
@@ -196,7 +196,7 @@ Insert::set_state (const XMLNode& node)
if ((prop = (*niter)->property ("path")) != 0) {
old_set_automation_state (*(*niter));
} else {
- set_automation_state (*(*niter));
+ set_automation_state (*(*niter), ParamID(PluginAutomation));
}
if ((prop = (*niter)->property ("visible")) != 0) {
@@ -211,7 +211,8 @@ Insert::set_state (const XMLNode& node)
if (sstr.fail()) {
break;
}
- mark_automation_visible (what, true);
+ // FIXME: other automation types?
+ mark_automation_visible (ParamID(PluginAutomation, what), true);
}
}
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 3069123f16..c60628b603 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -101,11 +101,10 @@ 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)
- : SessionObject(s, name),
- _output_buffers(new BufferSet()),
- _default_type(default_type),
+ : Automatable (s, name),
+ _output_buffers (new BufferSet()),
+ _default_type (default_type),
_gain_control (X_("gaincontrol"), *this),
- _gain_automation_curve (0.0, 2.0, 1.0),
_input_minimum (ChanCount::ZERO),
_input_maximum (ChanCount::INFINITE),
_output_minimum (ChanCount::ZERO),
@@ -136,12 +135,14 @@ IO::IO (Session& s, const string& name,
_phase_invert = false;
deferred_state = 0;
+ add_automation_parameter(new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0));
+
apply_gain_automation = false;
last_automation_snapshot = 0;
- _gain_automation_state = Off;
- _gain_automation_style = Absolute;
+ /*_gain_automation_state = Off;
+ _gain_automation_style = Absolute;*/
{
// IO::Meter is emitted from another thread so the
@@ -157,11 +158,10 @@ IO::IO (Session& s, const string& name,
}
IO::IO (Session& s, const XMLNode& node, DataType dt)
- : SessionObject(s, "unnamed io"),
- _output_buffers(new BufferSet()),
+ : Automatable (s, "unnamed io"),
+ _output_buffers (new BufferSet()),
_default_type (dt),
- _gain_control (X_("gaincontrol"), *this),
- _gain_automation_curve (0, 0, 0) // all reset in set_state()
+ _gain_control (X_("gaincontrol"), *this)
{
_meter = new PeakMeter (_session);
@@ -1129,7 +1129,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
gain_t
IO::effective_gain () const
{
- if (_gain_automation_curve.automation_playback()) {
+ if (gain_automation().automation_playback()) {
return _effective_gain;
} else {
return _desired_gain;
@@ -1288,18 +1288,9 @@ IO::state (bool full_state)
node->add_property ("iolimits", buf);
/* automation */
-
- if (full_state) {
-
- XMLNode* autonode = new XMLNode (X_("Automation"));
- autonode->add_child_nocopy (get_automation_state());
- node->add_child_nocopy (*autonode);
-
- snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state());
- } else {
- /* never store anything except Off for automation state in a template */
- snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off);
- }
+
+ if (full_state)
+ node->add_child_nocopy (get_automation_state());
return *node;
}
@@ -1363,7 +1354,7 @@ IO::set_state (const XMLNode& node)
if ((*iter)->name() == X_("Automation")) {
- set_automation_state (*(*iter)->children().front());
+ set_automation_state (*(*iter), ParamID(GainAutomation));
}
if ((*iter)->name() == X_("controllable")) {
@@ -1411,18 +1402,6 @@ IO::set_state (const XMLNode& node)
}
int
-IO::set_automation_state (const XMLNode& node)
-{
- return _gain_automation_curve.set_state (node);
-}
-
-XMLNode&
-IO::get_automation_state ()
-{
- return (_gain_automation_curve.get_state ());
-}
-
-int
IO::load_automation (string path)
{
string fullpath;
@@ -1479,7 +1458,7 @@ IO::load_automation (string path)
switch (type) {
case 'g':
- _gain_automation_curve.fast_simple_add (when, value);
+ gain_automation().fast_simple_add (when, value);
break;
case 's':
@@ -2198,41 +2177,43 @@ IO::meter ()
void
IO::clear_automation ()
{
- Glib::Mutex::Lock lm (automation_lock);
- _gain_automation_curve.clear ();
+ Automatable::clear_automation (); // clears gain automation
_panner->clear_automation ();
}
void
-IO::set_gain_automation_state (AutoState state)
+IO::set_parameter_automation_state (ParamID param, AutoState state)
{
- bool changed = false;
+ // XXX: would be nice to get rid of this special hack
- {
- Glib::Mutex::Lock lm (automation_lock);
+ if (param.type() == GainAutomation) {
- if (state != _gain_automation_curve.automation_state()) {
- changed = true;
- last_automation_snapshot = 0;
- _gain_automation_curve.set_automation_state (state);
-
- if (state != Off) {
- set_gain (_gain_automation_curve.eval (_session.transport_frame()), this);
+ bool changed = false;
+
+ {
+ Glib::Mutex::Lock lm (_automation_lock);
+
+ ARDOUR::AutomationList& gain_auto = gain_automation();
+
+ if (state != gain_auto.automation_state()) {
+ changed = true;
+ last_automation_snapshot = 0;
+ gain_auto.set_automation_state (state);
+
+ if (state != Off) {
+ // FIXME: shouldn't this use Curve?
+ set_gain (gain_auto.eval (_session.transport_frame()), this);
+ }
}
}
- }
- if (changed) {
- _session.set_dirty ();
- //gain_automation_state_changed (); /* EMIT SIGNAL */
- }
-}
+ if (changed) {
+ _session.set_dirty ();
+ }
-void
-IO::set_gain_automation_style (AutoStyle style)
-{
- Glib::Mutex::Lock lm (automation_lock);
- _gain_automation_curve.set_automation_style (style);
+ } else {
+ Automatable::set_parameter_automation_state(param, state);
+ }
}
void
@@ -2263,8 +2244,10 @@ IO::set_gain (gain_t val, void *src)
gain_changed (src);
_gain_control.Changed (); /* EMIT SIGNAL */
- if (_session.transport_stopped() && src != 0 && src != this && _gain_automation_curve.automation_write()) {
- _gain_automation_curve.add (_session.transport_frame(), val);
+ ARDOUR::AutomationList& gain_auto = gain_automation();
+
+ if (_session.transport_stopped() && src != 0 && src != this && gain_auto.automation_write()) {
+ gain_auto.add (_session.transport_frame(), val);
}
@@ -2272,18 +2255,6 @@ IO::set_gain (gain_t val, void *src)
}
void
-IO::start_gain_touch ()
-{
- _gain_automation_curve.start_touch ();
-}
-
-void
-IO::end_gain_touch ()
-{
- _gain_automation_curve.stop_touch ();
-}
-
-void
IO::start_pan_touch (uint32_t which)
{
if (which < _panner->size()) {
@@ -2305,8 +2276,10 @@ IO::automation_snapshot (nframes_t now)
{
if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
- if (_gain_automation_curve.automation_write()) {
- _gain_automation_curve.rt_add (now, gain());
+ ARDOUR::AutomationList& gain_auto = gain_automation();
+
+ if (gain_auto.automation_write()) {
+ gain_auto.rt_add (now, gain());
}
_panner->snapshot (now);
@@ -2318,15 +2291,18 @@ IO::automation_snapshot (nframes_t now)
void
IO::transport_stopped (nframes_t frame)
{
- _gain_automation_curve.reposition_for_rt_add (frame);
+ ARDOUR::AutomationList& gain_auto = gain_automation();
+
+ gain_auto.reposition_for_rt_add (frame);
- if (_gain_automation_curve.automation_state() != Off) {
+ if (gain_auto.automation_state() != Off) {
/* the src=0 condition is a special signal to not propagate
automation gain changes into the mix group when locating.
*/
- set_gain (_gain_automation_curve.eval (frame), 0);
+ // FIXME: shouldn't this use Curve?
+ set_gain (gain_auto.eval (frame), 0);
}
_panner->transport_stopped (frame);
diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc
index 0c2104ca7a..98a65546a9 100644
--- a/libs/ardour/ladspa_plugin.cc
+++ b/libs/ardour/ladspa_plugin.cc
@@ -318,7 +318,7 @@ LadspaPlugin::set_parameter (uint32_t which, float val)
{
if (which < descriptor->PortCount) {
shadow_data[which] = (LADSPA_Data) val;
- ParameterChanged (which, val); /* EMIT SIGNAL */
+ ParameterChanged (ParamID(PluginAutomation, which), val); /* EMIT SIGNAL */
if (which < parameter_count() && controls[which]) {
controls[which]->Changed ();
@@ -493,10 +493,10 @@ LadspaPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& des
string
-LadspaPlugin::describe_parameter (uint32_t which)
+LadspaPlugin::describe_parameter (ParamID which)
{
- if (which < parameter_count()) {
- return port_names()[which];
+ if (which.type() == PluginAutomation && which.id() < parameter_count()) {
+ return port_names()[which.id()];
} else {
return "??";
}
@@ -512,16 +512,16 @@ LadspaPlugin::latency () const
}
}
-set<uint32_t>
+set<ParamID>
LadspaPlugin::automatable () const
{
- set<uint32_t> ret;
+ set<ParamID> ret;
for (uint32_t i = 0; i < parameter_count(); ++i){
if (LADSPA_IS_PORT_INPUT(port_descriptor (i)) &&
LADSPA_IS_PORT_CONTROL(port_descriptor (i))){
- ret.insert (ret.end(), i);
+ ret.insert (ret.end(), ParamID(PluginAutomation, i));
}
}
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index a56f1d0392..d5a238e253 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -190,7 +190,7 @@ StreamPanner::add_state (XMLNode& node)
/*---------------------------------------------------------------------- */
BaseStereoPanner::BaseStereoPanner (Panner& p)
- : StreamPanner (p), _automation (0.0, 1.0, 0.5)
+ : StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5)
{
}
@@ -438,7 +438,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob
/* fetch positional data */
- if (!_automation.rt_safe_get_vector (start, end, buffers[0], nframes)) {
+ if (!_automation.curve().rt_safe_get_vector (start, end, buffers[0], nframes)) {
/* fallback */
if (!_muted) {
distribute (srcbuf, obufs, 1.0, nframes);
@@ -565,7 +565,7 @@ EqualPowerStereoPanner::set_state (const XMLNode& node)
/*----------------------------------------------------------------------*/
Multi2dPanner::Multi2dPanner (Panner& p)
- : StreamPanner (p), _automation (0.0, 1.0, 0.5) // XXX useless
+ : StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5) // XXX useless
{
update ();
}
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index b1cb97a475..1b93ecf82b 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -94,7 +94,7 @@ Plugin::get_nth_control (uint32_t n)
get_parameter_descriptor (n, desc);
- controls[n] = new PortControllable (describe_parameter (n), *this, n,
+ controls[n] = new PortControllable (describe_parameter (ParamID(PluginAutomation, n)), *this, n,
desc.lower, desc.upper, desc.toggled, desc.logarithmic);
}
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index baf22a6863..1b0130fc37 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -152,18 +152,21 @@ PluginInsert::~PluginInsert ()
}
void
-PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
+PluginInsert::automation_list_creation_callback (ParamID which, AutomationList& alist)
{
alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
}
void
-PluginInsert::auto_state_changed (uint32_t which)
+PluginInsert::auto_state_changed (ParamID which)
{
- AutomationList& alist (automation_list (which));
+ if (which.type() != PluginAutomation)
+ return;
+
+ AutomationList* alist = automation_list (which);
- if (alist.automation_state() != Off) {
- _plugins[0]->set_parameter (which, alist.eval (_session.transport_frame()));
+ if (alist && alist->automation_state() != Off) {
+ _plugins[0]->set_parameter (which.id(), alist->eval (_session.transport_frame()));
}
}
@@ -210,18 +213,21 @@ PluginInsert::is_generator() const
void
PluginInsert::set_automatable ()
{
- set<uint32_t> a;
+ set<ParamID> a;
a = _plugins.front()->automatable ();
- for (set<uint32_t>::iterator i = a.begin(); i != a.end(); ++i) {
+ for (set<ParamID>::iterator i = a.begin(); i != a.end(); ++i) {
can_automate (*i);
}
}
void
-PluginInsert::parameter_changed (uint32_t which, float val)
+PluginInsert::parameter_changed (ParamID which, float val)
{
+ if (which.type() != PluginAutomation)
+ return;
+
vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin();
/* don't set the first plugin, just all the slaves */
@@ -270,14 +276,14 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
if (with_auto) {
- map<uint32_t,AutomationList*>::iterator li;
+ map<ParamID,AutomationList*>::iterator li;
uint32_t n;
for (n = 0, li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li, ++n) {
AutomationList& alist (*((*li).second));
- if (alist.automation_playback()) {
+ if (alist.param_id().type() == PluginAutomation && alist.automation_playback()) {
bool valid;
float val = alist.rt_safe_eval (now, valid);
@@ -301,12 +307,13 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
void
PluginInsert::automation_snapshot (nframes_t now)
{
- map<uint32_t,AutomationList*>::iterator li;
+ map<ParamID,AutomationList*>::iterator li;
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
AutomationList *alist = ((*li).second);
- if (alist != 0 && alist->automation_write ()) {
+ if (alist != 0 && alist->param_id().type() == PluginAutomation
+ && alist->automation_write ()) {
float val = _plugins[0]->get_parameter ((*li).first);
alist->rt_add (now, val);
@@ -318,13 +325,13 @@ PluginInsert::automation_snapshot (nframes_t now)
void
PluginInsert::transport_stopped (nframes_t now)
{
- map<uint32_t,AutomationList*>::iterator li;
+ map<ParamID,AutomationList*>::iterator li;
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
AutomationList& alist (*(li->second));
alist.reposition_for_rt_add (now);
- if (alist.automation_state() != Off) {
+ if (alist.param_id().type() == PluginAutomation && alist.automation_state() != Off) {
_plugins[0]->set_parameter (li->first, alist.eval (now));
}
}
@@ -374,14 +381,17 @@ PluginInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
}
void
-PluginInsert::set_parameter (uint32_t port, float val)
+PluginInsert::set_parameter (ParamID param, float val)
{
+ if (param.type() != PluginAutomation)
+ return;
+
/* the others will be set from the event triggered by this */
- _plugins[0]->set_parameter (port, val);
+ _plugins[0]->set_parameter (param.id(), val);
- if (automation_list (port).automation_write()) {
- automation_list (port).add (_session.audible_frame(), val);
+ if (automation_list (param) && automation_list (param)->automation_write()) {
+ automation_list (param)->add (_session.audible_frame(), val);
}
_session.set_dirty();
@@ -432,63 +442,18 @@ PluginInsert::automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offs
}
float
-PluginInsert::default_parameter_value (uint32_t port)
+PluginInsert::default_parameter_value (ParamID param)
{
+ if (param.type() != PluginAutomation)
+ return 1.0;
+
if (_plugins.empty()) {
fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
<< endmsg;
/*NOTREACHED*/
}
- return _plugins[0]->default_value (port);
-}
-
-void
-PluginInsert::set_port_automation_state (uint32_t port, AutoState s)
-{
- if (port < _plugins[0]->parameter_count()) {
-
- AutomationList& al = automation_list (port);
-
- if (s != al.automation_state()) {
- al.set_automation_state (s);
- _session.set_dirty ();
- }
- }
-}
-
-AutoState
-PluginInsert::get_port_automation_state (uint32_t port)
-{
- if (port < _plugins[0]->parameter_count()) {
- return automation_list (port).automation_state();
- } else {
- return Off;
- }
-}
-
-void
-PluginInsert::protect_automation ()
-{
- set<uint32_t> automated_params;
-
- what_has_automation (automated_params);
-
- for (set<uint32_t>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
-
- AutomationList& al = automation_list (*i);
-
- switch (al.automation_state()) {
- case Write:
- al.set_automation_state (Off);
- break;
- case Touch:
- al.set_automation_state (Play);
- break;
- default:
- break;
- }
- }
+ return _plugins[0]->default_value (param.id());
}
boost::shared_ptr<Plugin>
@@ -684,16 +649,18 @@ PluginInsert::state (bool full)
/* add port automation state */
XMLNode *autonode = new XMLNode(port_automation_node_name);
- set<uint32_t> automatable = _plugins[0]->automatable();
+ set<ParamID> automatable = _plugins[0]->automatable();
- for (set<uint32_t>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
+ for (set<ParamID>::iterator x = automatable.begin(); x != automatable.end(); ++x) {
- XMLNode* child = new XMLNode("port");
+ /*XMLNode* child = new XMLNode("port");
snprintf(buf, sizeof(buf), "%" PRIu32, *x);
child->add_property("number", string(buf));
child->add_child_nocopy (automation_list (*x).state (full));
autonode->add_child_nocopy (*child);
+ */
+ autonode->add_child_nocopy (automation_list (*x)->state (full));
}
node.add_child_nocopy (*autonode);
@@ -824,7 +791,7 @@ PluginInsert::set_state(const XMLNode& node)
}
if (!child->children().empty()) {
- automation_list (port_id).set_state (*child->children().front());
+ automation_list (ParamID(PluginAutomation, port_id), true)->set_state (*child->children().front());
} else {
if ((cprop = child->property("auto")) != 0) {
@@ -832,13 +799,13 @@ PluginInsert::set_state(const XMLNode& node)
int x;
sscanf (cprop->value().c_str(), "0x%x", &x);
- automation_list (port_id).set_automation_state (AutoState (x));
+ automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (AutoState (x));
} else {
/* missing */
- automation_list (port_id).set_automation_state (Off);
+ automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (Off);
}
}
@@ -860,9 +827,12 @@ PluginInsert::set_state(const XMLNode& node)
}
string
-PluginInsert::describe_parameter (uint32_t what)
+PluginInsert::describe_parameter (ParamID param)
{
- return _plugins[0]->describe_parameter (what);
+ if (param.type() != PluginAutomation)
+ return Automatable::describe_parameter(param);
+
+ return _plugins[0]->describe_parameter (param);
}
ARDOUR::nframes_t
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 883bc0f6aa..3353149efa 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -2380,12 +2380,14 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra
apply_gain_automation = false;
{
- Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK);
+ Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK);
if (am.locked() && _session.transport_rolling()) {
- if (_gain_automation_curve.automation_playback()) {
- apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+ ARDOUR::AutomationList& gain_auto = gain_automation();
+
+ if (gain_auto.automation_playback()) {
+ apply_gain_automation = gain_auto.curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
}
}
}
@@ -2562,33 +2564,10 @@ Route::set_block_size (nframes_t nframes)
void
Route::protect_automation ()
{
- switch (gain_automation_state()) {
- case Write:
- set_gain_automation_state (Off);
- case Touch:
- set_gain_automation_state (Play);
- break;
- default:
- break;
- }
-
- switch (panner().automation_state ()) {
- case Write:
- panner().set_automation_state (Off);
- break;
- case Touch:
- panner().set_automation_state (Play);
- break;
- default:
- break;
- }
+ Automatable::protect_automation();
- for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i) {
- boost::shared_ptr<PluginInsert> pi;
- if ((pi = boost::dynamic_pointer_cast<PluginInsert> (*i)) != 0) {
- pi->protect_automation ();
- }
- }
+ for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i)
+ (*i)->protect_automation();
}
void
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index aee4d4004c..37867a2cfa 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -103,7 +103,7 @@ Send::set_state(const XMLNode& node)
if ((*niter)->name() == "Redirect") {
insert_node = *niter;
} else if ((*niter)->name() == X_("Automation")) {
- _io->set_automation_state (*(*niter));
+ _io->set_automation_state (*(*niter), ParamID(GainAutomation));
}
}
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index b192857079..16b35397cf 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -1019,7 +1019,7 @@ void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal )
// TODO handle plugin automation polling
void MackieControlProtocol::update_automation( RouteSignal & rs )
{
- ARDOUR::AutoState gain_state = rs.route().gain_automation_state();
+ ARDOUR::AutoState gain_state = rs.route().gain_automation().automation_state();
if ( gain_state == Touch || gain_state == Play )
{
notify_gain_changed( &rs );