diff options
Diffstat (limited to 'libs')
32 files changed, 698 insertions, 506 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index dd76aadcba..f93c19649f 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -77,6 +77,7 @@ gdither.cc globals.cc import.cc automatable.cc +automation_control.cc processor.cc io_processor.cc plugin_insert.cc diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index db763876b0..52a07679af 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; } - AutomationList& fade_in() { return _fade_in; } - AutomationList& fade_out() { return _fade_out; } - AutomationList& envelope() { return _envelope; } + boost::shared_ptr<AutomationList> fade_in() { return _fade_in; } + boost::shared_ptr<AutomationList> fade_out() { return _fade_out; } + boost::shared_ptr<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 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; + boost::shared_ptr<AutomationList> _fade_in; + FadeShape _fade_in_shape; + boost::shared_ptr<AutomationList> _fade_out; + FadeShape _fade_out_shape; + boost::shared_ptr<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 f6d6d86ed0..a1161db80d 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000,2007 Paul Davis + Copyright (C) 2000, 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 @@ -22,13 +22,16 @@ #include <set> #include <map> +#include <boost/shared_ptr.hpp> #include <ardour/session_object.h> #include <ardour/automation_event.h> +#include <ardour/automation_control.h> #include <ardour/param_id.h> namespace ARDOUR { class Session; +class AutomationControl; class Automatable : public SessionObject { @@ -38,16 +41,17 @@ public: virtual ~Automatable() {} // shorthand for gain, pan, etc - inline AutomationList* automation_list(AutomationType type, bool create_if_missing=false) { - return automation_list(ParamID(type), create_if_missing); + inline boost::shared_ptr<AutomationControl> + control(AutomationType type, bool create_if_missing=false) { + return control(ParamID(type), create_if_missing); } - virtual AutomationList* automation_list(ParamID id, bool create_if_missing=false); - virtual const AutomationList* automation_list(ParamID id) const; + virtual boost::shared_ptr<AutomationControl> control(ParamID id, bool create_if_missing=false); + virtual boost::shared_ptr<const AutomationControl> control(ParamID id) const; - virtual void add_automation_parameter(AutomationList* al); + virtual void add_control(boost::shared_ptr<AutomationControl>); - virtual void automation_snapshot(nframes_t now) {}; + virtual void automation_snapshot(nframes_t now); virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const; @@ -74,7 +78,7 @@ protected: void can_automate(ParamID); - virtual void automation_list_creation_callback(ParamID, AutomationList&) {} + virtual void auto_state_changed (ParamID which) {} int set_automation_state(const XMLNode&, ParamID default_param); XMLNode& get_automation_state(); @@ -83,9 +87,11 @@ protected: int old_set_automation_state(const XMLNode&); mutable Glib::Mutex _automation_lock; - - std::map<ParamID,AutomationList*> _parameter_automation; - std::set<ParamID> _visible_parameter_automation; + + typedef std::map<ParamID,boost::shared_ptr<AutomationControl> > Controls; + + Controls _controls; + std::set<ParamID> _visible_controls; std::set<ParamID> _can_automate_list; nframes_t _last_automation_snapshot; diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h new file mode 100644 index 0000000000..d9e7a232af --- /dev/null +++ b/libs/ardour/ardour/automation_control.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + 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_automation_control_h__ +#define __ardour_automation_control_h__ + +#include <boost/shared_ptr.hpp> +#include <pbd/controllable.h> + +namespace ARDOUR { + +class AutomationList; +class Session; + + +/** A PBD:Controllable with associated automation data (AutomationList) + */ +class AutomationControl : public PBD::Controllable +{ +public: + AutomationControl(ARDOUR::Session&, boost::shared_ptr<ARDOUR::AutomationList>, + std::string name="unnamed controllable"); + + void set_value(float val); + float get_value() const; + float user_value() const; + + void set_list(boost::shared_ptr<ARDOUR::AutomationList>); + + boost::shared_ptr<ARDOUR::AutomationList> list() { return _list; } + boost::shared_ptr<const ARDOUR::AutomationList> list() const { return _list; } + +protected: + ARDOUR::Session& _session; + boost::shared_ptr<ARDOUR::AutomationList> _list; + float _user_value; +}; + + +} // namespace ARDOUR + +#endif /* __ardour_automation_control_h__ */ diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index fc49f0699f..60e1fc25f1 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -42,6 +42,7 @@ #include <ardour/port_set.h> #include <ardour/chan_count.h> #include <ardour/latent.h> +#include <ardour/automation_control.h> using std::string; using std::vector; @@ -60,6 +61,7 @@ class AudioPort; class MidiPort; class BufferSet; + /** A collection of input and output ports with connections. * * An IO can contain ports of varying types, making routes/inserts/etc with @@ -103,8 +105,6 @@ class IO : public Automatable, public Latent void just_meter_input (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset); - virtual void set_gain (gain_t g, void *src); - void inc_gain (gain_t delta, void *src); gain_t gain () const { return _desired_gain; } virtual gain_t effective_gain () const; @@ -182,8 +182,6 @@ class IO : public Automatable, public Latent sigc::signal<void,IOChange,void*> input_changed; sigc::signal<void,IOChange,void*> output_changed; - sigc::signal<void,void*> gain_changed; - virtual XMLNode& state (bool full); XMLNode& get_state (void); int set_state (const XMLNode&); @@ -206,10 +204,6 @@ class IO : public Automatable, public Latent static sigc::signal<void,ChanCount> MoreChannels; static sigc::signal<int> PortsCreated; - PBD::Controllable& gain_control() { - return _gain_control; - } - static void update_meters(); private: @@ -221,13 +215,24 @@ class IO : public Automatable, public Latent public: /* automation */ + + struct GainControl : public AutomationControl { + GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al) + : AutomationControl (i._session, al, name) + , _io (i) + {} + + void set_value (float val); + float get_value (void) const; + + IO& _io; + }; - static void set_automation_interval (nframes_t frames) { - _automation_interval = frames; + boost::shared_ptr<GainControl> gain_control() { + return _gain_control; } - - static nframes_t automation_interval() { - return _automation_interval; + boost::shared_ptr<const GainControl> gain_control() const { + return _gain_control; } void clear_automation (); @@ -237,10 +242,6 @@ class IO : public Automatable, public Latent virtual void transport_stopped (nframes_t now); // interface: matches Insert void automation_snapshot (nframes_t now); // interface: matches Automatable - // 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); @@ -282,25 +283,12 @@ class IO : public Automatable, public Latent virtual uint32_t pans_required() const { return _inputs.count().n_audio(); } - struct GainControllable : public PBD::Controllable { - GainControllable (std::string name, IO& i) : Controllable (name), io (i) {} - - void set_value (float val); - float get_value (void) const; - - IO& io; - }; - - GainControllable _gain_control; + boost::shared_ptr<GainControl> _gain_control; - nframes_t last_automation_snapshot; - static nframes_t _automation_interval; - - /*AutoState _gain_automation_state; - AutoStyle _gain_automation_style;*/ + virtual void set_gain (gain_t g, void *src); + void inc_gain (gain_t delta, void *src); bool apply_gain_automation; - //Curve _gain_automation_curve; virtual int load_automation (std::string path); diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index af3cda94e2..89f56e03c5 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -76,14 +76,14 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful virtual void set_automation_state (AutoState) = 0; virtual void set_automation_style (AutoStyle) = 0; - PBD::Controllable& control() { return _control; } + boost::shared_ptr<PBD::Controllable> control() { return _control; } /* 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 AutomationList& automation() = 0; + virtual boost::shared_ptr<AutomationList> automation() = 0; sigc::signal<void> Changed; /* for position */ sigc::signal<void> StateChanged; /* for mute */ @@ -125,7 +125,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful bool can_send_feedback() const; }; - PanControllable _control; + boost::shared_ptr<PanControllable> _control; void add_state (XMLNode&); virtual void update () = 0; @@ -151,7 +151,7 @@ class BaseStereoPanner : public StreamPanner void set_automation_style (AutoStyle); /* TODO: StreamPanner is-a Automatable? */ - AutomationList& automation() { return _automation; } + boost::shared_ptr<AutomationList> automation() { return _automation; } /* old school automation loading */ @@ -165,7 +165,7 @@ class BaseStereoPanner : public StreamPanner float left_interp; float right_interp; - AutomationList _automation; + boost::shared_ptr<AutomationList> _automation; }; class EqualPowerStereoPanner : public BaseStereoPanner @@ -208,7 +208,7 @@ class Multi2dPanner : public StreamPanner /* TODO: StreamPanner is-a Automatable? */ - AutomationList& automation() { return _automation; } + boost::shared_ptr<AutomationList> automation() { return _automation; } void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); void distribute_automated (AudioBuffer& src, BufferSet& obufs, @@ -226,7 +226,7 @@ class Multi2dPanner : public StreamPanner int load (istream&, string path, uint32_t&); private: - AutomationList _automation; + boost::shared_ptr<AutomationList> _automation; void update (); }; diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index e3b1b62b19..90c83057df 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -109,7 +109,6 @@ class PluginInsert : public Processor void init (); void set_automatable (); 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/processor.h b/libs/ardour/ardour/processor.h index 3985306d01..371572610a 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -80,7 +80,7 @@ class Processor : public Automatable, public Latent virtual bool configure_io (ChanCount in, ChanCount out) { _configured_input = in; return (_configured = true); } - /* Act as a pass through, if not overridden */ + /* Derived classes should override these, or processor appears as a pass-through */ virtual bool can_support_input_configuration (ChanCount in) const { return true; } virtual ChanCount output_for_input_configuration (ChanCount in) const { return in; } virtual ChanCount output_streams() const { return _configured_input; } diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index b8c9431e42..1fd6eff0f8 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -81,9 +81,9 @@ class Route : public IO long order_key (const char* name) const; void set_order_key (const char* name, long n); - bool hidden() const { return _flags & Hidden; } - bool master() const { return _flags & MasterOut; } - bool control() const { return _flags & ControlOut; } + bool is_hidden() const { return _flags & Hidden; } + bool is_master() const { return _flags & MasterOut; } + bool is_control() const { return _flags & ControlOut; } /* these are the core of the API of a Route. see the protected sections as well */ @@ -243,11 +243,11 @@ class Route : public IO ToggleType type; }; - PBD::Controllable& solo_control() { + boost::shared_ptr<PBD::Controllable> solo_control() { return _solo_control; } - PBD::Controllable& mute_control() { + boost::shared_ptr<PBD::Controllable> mute_control() { return _mute_control; } @@ -306,8 +306,8 @@ class Route : public IO std::string _comment; bool _have_internal_generator; - ToggleControllable _solo_control; - ToggleControllable _mute_control; + boost::shared_ptr<ToggleControllable> _solo_control; + boost::shared_ptr<ToggleControllable> _mute_control; nframes_t check_initial_delay (nframes_t, nframes_t&, nframes_t&); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 3a4a21cb8a..2c4c60a911 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -649,9 +649,11 @@ class Session : public PBD::StatefulDestructible sigc::signal<void> NamedSelectionAdded; sigc::signal<void> NamedSelectionRemoved; - /* Curves and AutomationLists (TODO when they go away) */ - void add_curve(Curve*); - void add_automation_list(AutomationList*); + /* Curves and AutomationLists (TODO when they go away) */ + void add_curve(Curve*); + void add_automation_list(AutomationList*); + + nframes_t automation_interval () const { return _automation_interval; } /* fade curves */ @@ -780,9 +782,9 @@ class Session : public PBD::StatefulDestructible std::map<PBD::ID, PBD::StatefulThingWithGoingAway*> registry; - // these commands are implemented in libs/ardour/session_command.cc + // these commands are implemented in libs/ardour/session_command.cc Command* memento_command_factory(XMLNode* n); - void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway*); + void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway*); Command* global_state_command_factory (const XMLNode& n); @@ -917,9 +919,9 @@ class Session : public PBD::StatefulDestructible /* Controllables */ - PBD::Controllable* controllable_by_id (const PBD::ID&); + boost::shared_ptr<PBD::Controllable> controllable_by_id (const PBD::ID&); - void add_controllable (PBD::Controllable*); + void add_controllable (boost::shared_ptr<PBD::Controllable>); void remove_controllable (PBD::Controllable*); protected: @@ -1648,6 +1650,8 @@ class Session : public PBD::StatefulDestructible void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force); uint32_t _npan_buffers; + nframes_t _automation_interval; + /* VST support */ long _vst_callback (VSTPlugin*, @@ -1672,7 +1676,7 @@ class Session : public PBD::StatefulDestructible LayerModel layer_model; CrossfadeModel xfade_model; - typedef std::set<PBD::Controllable*> Controllables; + typedef std::set<boost::shared_ptr<PBD::Controllable> > Controllables; Glib::Mutex controllables_lock; Controllables controllables; diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 06ce398896..4d5545c0dc 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -83,7 +83,7 @@ class Track : public Route XMLNode& get_template(); virtual int set_state(const XMLNode& node) = 0; - PBD::Controllable& rec_enable_control() { return _rec_enable_control; } + boost::shared_ptr<PBD::Controllable> rec_enable_control() { return _rec_enable_control; } bool record_enabled() const; void set_record_enable (bool yn, void *src); @@ -141,8 +141,9 @@ class Track : public Route XMLNode* pending_state; sigc::connection recenable_connection; sigc::connection ic_connection; - RecEnableControllable _rec_enable_control; bool _destructive; + + boost::shared_ptr<RecEnableControllable> _rec_enable_control; }; }; /* namespace ARDOUR*/ diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 9f13aee465..4df8ffea49 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -278,8 +278,8 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base) child = *niter; if (child->name() == X_("recenable")) { - _rec_enable_control.set_state (*child); - _session.add_controllable (&_rec_enable_control); + _rec_enable_control->set_state (*child); + _session.add_controllable (_rec_enable_control); } } @@ -334,7 +334,7 @@ AudioTrack::state(bool full_state) _diskstream->id().print (buf, sizeof (buf)); root.add_property ("diskstream-id", buf); - root.add_child_nocopy (_rec_enable_control.get_state()); + root.add_child_nocopy (_rec_enable_control->get_state()); return root; } @@ -601,8 +601,8 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, if (!diskstream->record_enabled() && _session.transport_rolling()) { Glib::Mutex::Lock am (_automation_lock, Glib::TRY_LOCK); - 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); + if (am.locked() && gain_control()->list()->automation_playback()) { + apply_gain_automation = gain_control()->list()->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 (IO::gain_automation().automation_state() == Play) { + if (gain_control()->list()->automation_state() == Play) { - IO::gain_automation().curve().get_vector (start, start + nframes, gain_automation, nframes); + gain_control()->list()->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 a7a5fca912..359c729368 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -72,20 +72,20 @@ 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 (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) + : Region (start, length, name, DataType::AUDIO) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)) { init (); } /** 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 (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) + : Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0, Region::Flag(Region::DefaultFlags|Region::External)) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(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 (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) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(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 (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) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)) { init (); } @@ -123,10 +123,10 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c /** Create a new AudioRegion, that is part of an existing one */ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags) - : Region (other, offset, length, name, layer, flags), - _fade_in (other->_fade_in), - _fade_out (other->_fade_out), - _envelope (other->_envelope, (double) offset, (double) offset + length) + : Region (other, offset, length, name, layer, flags) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)) { /* return to default fades if the existing ones are too long */ _fade_in_disabled = 0; @@ -134,7 +134,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t if (_flags & LeftOfSplit) { - if (_fade_in.back()->when >= _length) { + if (_fade_in->back()->when >= _length) { set_default_fade_in (); } else { _fade_in_disabled = other->_fade_in_disabled; @@ -144,7 +144,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t } if (_flags & RightOfSplit) { - if (_fade_out.back()->when >= _length) { + if (_fade_out->back()->when >= _length) { set_default_fade_out (); } else { _fade_out_disabled = other->_fade_out_disabled; @@ -161,10 +161,10 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t } AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other) - : Region (other), - _fade_in (other->_fade_in), - _fade_out (other->_fade_out), - _envelope (other->_envelope) + : Region (other) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)) { _scale_amplitude = other->_scale_amplitude; _envelope = other->_envelope; @@ -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 (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) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)) { boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src); if (afs) { @@ -201,9 +201,9 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node) : 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) + , _fade_in (new AutomationList(ParamID(FadeInAutomation), 0.0, 2.0, 1.0)) + , _fade_out (new AutomationList(ParamID(FadeOutAutomation), 0.0, 2.0, 1.0)) + , _envelope (new AutomationList(ParamID(EnvelopeAutomation), 0.0, 2.0, 1.0)) { set_default_fades (); _scale_amplitude = 1.0; @@ -224,9 +224,9 @@ AudioRegion::~AudioRegion () void AudioRegion::listen_to_my_curves () { - _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); - _fade_in.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed)); - _fade_out.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed)); + _envelope->StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed)); + _fade_in->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed)); + _fade_out->StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed)); } bool @@ -395,7 +395,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff if (_flags & FadeIn) { - nframes_t fade_in_length = (nframes_t) _fade_in.back()->when; + nframes_t fade_in_length = (nframes_t) _fade_in->back()->when; /* see if this read is within the fade in */ @@ -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.curve().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]; @@ -436,7 +436,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff */ - nframes_t fade_out_length = (nframes_t) _fade_out.back()->when; + nframes_t fade_out_length = (nframes_t) _fade_out->back()->when; nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length); nframes_t fade_interval_end = min(internal_offset + to_read, _length); @@ -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.curve().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.curve().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) { @@ -521,7 +521,7 @@ AudioRegion::state (bool full) if ((_flags & DefaultFadeIn)) { child->add_property (X_("default"), X_("yes")); } else { - child->add_child_nocopy (_fade_in.get_state ()); + child->add_child_nocopy (_fade_in->get_state ()); } child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes")); @@ -531,7 +531,7 @@ AudioRegion::state (bool full) if ((_flags & DefaultFadeOut)) { child->add_property (X_("default"), X_("yes")); } else { - child->add_child_nocopy (_fade_out.get_state ()); + child->add_child_nocopy (_fade_out->get_state ()); } child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes")); @@ -545,10 +545,10 @@ AudioRegion::state (bool full) // If there are only two points, the points are in the start of the region and the end of the region // so, if they are both at 1.0f, that means the default region. - if (_envelope.size() == 2 && - _envelope.front()->value == 1.0f && - _envelope.back()->value==1.0f) { - if (_envelope.front()->when == 0 && _envelope.back()->when == _length) { + if (_envelope->size() == 2 && + _envelope->front()->value == 1.0f && + _envelope->back()->value==1.0f) { + if (_envelope->front()->when == 0 && _envelope->back()->when == _length) { default_env = true; } } @@ -556,7 +556,7 @@ AudioRegion::state (bool full) if (default_env) { child->add_property ("default", "yes"); } else { - child->add_child_nocopy (_envelope.get_state ()); + child->add_child_nocopy (_envelope->get_state ()); } } else { @@ -617,28 +617,28 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen if (child->name() == "Envelope") { - _envelope.clear (); + _envelope->clear (); - if ((prop = child->property ("default")) != 0 || _envelope.set_state (*child)) { + if ((prop = child->property ("default")) != 0 || _envelope->set_state (*child)) { set_default_envelope (); } - _envelope.set_max_xval (_length); - _envelope.truncate_end (_length); + _envelope->set_max_xval (_length); + _envelope->truncate_end (_length); } else if (child->name() == "FadeIn") { - _fade_in.clear (); + _fade_in->clear (); - if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in.set_state (*child)) { + if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in->set_state (*child)) { set_default_fade_in (); } } else if (child->name() == "FadeOut") { - _fade_out.clear (); + _fade_out->clear (); - if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out.set_state (*child)) { + if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out->set_state (*child)) { set_default_fade_out (); } } @@ -665,70 +665,70 @@ AudioRegion::set_state (const XMLNode& node) void AudioRegion::set_fade_in_shape (FadeShape shape) { - set_fade_in (shape, (nframes_t) _fade_in.back()->when); + set_fade_in (shape, (nframes_t) _fade_in->back()->when); } void AudioRegion::set_fade_out_shape (FadeShape shape) { - set_fade_out (shape, (nframes_t) _fade_out.back()->when); + set_fade_out (shape, (nframes_t) _fade_out->back()->when); } void AudioRegion::set_fade_in (FadeShape shape, nframes_t len) { - _fade_in.freeze (); - _fade_in.clear (); + _fade_in->freeze (); + _fade_in->clear (); switch (shape) { case Linear: - _fade_in.fast_simple_add (0.0, 0.0); - _fade_in.fast_simple_add (len, 1.0); + _fade_in->fast_simple_add (0.0, 0.0); + _fade_in->fast_simple_add (len, 1.0); break; case Fast: - _fade_in.fast_simple_add (0, 0); - _fade_in.fast_simple_add (len * 0.389401, 0.0333333); - _fade_in.fast_simple_add (len * 0.629032, 0.0861111); - _fade_in.fast_simple_add (len * 0.829493, 0.233333); - _fade_in.fast_simple_add (len * 0.9447, 0.483333); - _fade_in.fast_simple_add (len * 0.976959, 0.697222); - _fade_in.fast_simple_add (len, 1); + _fade_in->fast_simple_add (0, 0); + _fade_in->fast_simple_add (len * 0.389401, 0.0333333); + _fade_in->fast_simple_add (len * 0.629032, 0.0861111); + _fade_in->fast_simple_add (len * 0.829493, 0.233333); + _fade_in->fast_simple_add (len * 0.9447, 0.483333); + _fade_in->fast_simple_add (len * 0.976959, 0.697222); + _fade_in->fast_simple_add (len, 1); break; case Slow: - _fade_in.fast_simple_add (0, 0); - _fade_in.fast_simple_add (len * 0.0207373, 0.197222); - _fade_in.fast_simple_add (len * 0.0645161, 0.525); - _fade_in.fast_simple_add (len * 0.152074, 0.802778); - _fade_in.fast_simple_add (len * 0.276498, 0.919444); - _fade_in.fast_simple_add (len * 0.481567, 0.980556); - _fade_in.fast_simple_add (len * 0.767281, 1); - _fade_in.fast_simple_add (len, 1); + _fade_in->fast_simple_add (0, 0); + _fade_in->fast_simple_add (len * 0.0207373, 0.197222); + _fade_in->fast_simple_add (len * 0.0645161, 0.525); + _fade_in->fast_simple_add (len * 0.152074, 0.802778); + _fade_in->fast_simple_add (len * 0.276498, 0.919444); + _fade_in->fast_simple_add (len * 0.481567, 0.980556); + _fade_in->fast_simple_add (len * 0.767281, 1); + _fade_in->fast_simple_add (len, 1); break; case LogA: - _fade_in.fast_simple_add (0, 0); - _fade_in.fast_simple_add (len * 0.0737327, 0.308333); - _fade_in.fast_simple_add (len * 0.246544, 0.658333); - _fade_in.fast_simple_add (len * 0.470046, 0.886111); - _fade_in.fast_simple_add (len * 0.652074, 0.972222); - _fade_in.fast_simple_add (len * 0.771889, 0.988889); - _fade_in.fast_simple_add (len, 1); + _fade_in->fast_simple_add (0, 0); + _fade_in->fast_simple_add (len * 0.0737327, 0.308333); + _fade_in->fast_simple_add (len * 0.246544, 0.658333); + _fade_in->fast_simple_add (len * 0.470046, 0.886111); + _fade_in->fast_simple_add (len * 0.652074, 0.972222); + _fade_in->fast_simple_add (len * 0.771889, 0.988889); + _fade_in->fast_simple_add (len, 1); break; case LogB: - _fade_in.fast_simple_add (0, 0); - _fade_in.fast_simple_add (len * 0.304147, 0.0694444); - _fade_in.fast_simple_add (len * 0.529954, 0.152778); - _fade_in.fast_simple_add (len * 0.725806, 0.333333); - _fade_in.fast_simple_add (len * 0.847926, 0.558333); - _fade_in.fast_simple_add (len * 0.919355, 0.730556); - _fade_in.fast_simple_add (len, 1); + _fade_in->fast_simple_add (0, 0); + _fade_in->fast_simple_add (len * 0.304147, 0.0694444); + _fade_in->fast_simple_add (len * 0.529954, 0.152778); + _fade_in->fast_simple_add (len * 0.725806, 0.333333); + _fade_in->fast_simple_add (len * 0.847926, 0.558333); + _fade_in->fast_simple_add (len * 0.919355, 0.730556); + _fade_in->fast_simple_add (len, 1); break; } - _fade_in.thaw (); + _fade_in->thaw (); _fade_in_shape = shape; send_change (FadeInChanged); @@ -737,56 +737,56 @@ AudioRegion::set_fade_in (FadeShape shape, nframes_t len) void AudioRegion::set_fade_out (FadeShape shape, nframes_t len) { - _fade_out.freeze (); - _fade_out.clear (); + _fade_out->freeze (); + _fade_out->clear (); switch (shape) { case Fast: - _fade_out.fast_simple_add (len * 0, 1); - _fade_out.fast_simple_add (len * 0.023041, 0.697222); - _fade_out.fast_simple_add (len * 0.0553, 0.483333); - _fade_out.fast_simple_add (len * 0.170507, 0.233333); - _fade_out.fast_simple_add (len * 0.370968, 0.0861111); - _fade_out.fast_simple_add (len * 0.610599, 0.0333333); - _fade_out.fast_simple_add (len * 1, 0); + _fade_out->fast_simple_add (len * 0, 1); + _fade_out->fast_simple_add (len * 0.023041, 0.697222); + _fade_out->fast_simple_add (len * 0.0553, 0.483333); + _fade_out->fast_simple_add (len * 0.170507, 0.233333); + _fade_out->fast_simple_add (len * 0.370968, 0.0861111); + _fade_out->fast_simple_add (len * 0.610599, 0.0333333); + _fade_out->fast_simple_add (len * 1, 0); break; case LogA: - _fade_out.fast_simple_add (len * 0, 1); - _fade_out.fast_simple_add (len * 0.228111, 0.988889); - _fade_out.fast_simple_add (len * 0.347926, 0.972222); - _fade_out.fast_simple_add (len * 0.529954, 0.886111); - _fade_out.fast_simple_add (len * 0.753456, 0.658333); - _fade_out.fast_simple_add (len * 0.9262673, 0.308333); - _fade_out.fast_simple_add (len * 1, 0); + _fade_out->fast_simple_add (len * 0, 1); + _fade_out->fast_simple_add (len * 0.228111, 0.988889); + _fade_out->fast_simple_add (len * 0.347926, 0.972222); + _fade_out->fast_simple_add (len * 0.529954, 0.886111); + _fade_out->fast_simple_add (len * 0.753456, 0.658333); + _fade_out->fast_simple_add (len * 0.9262673, 0.308333); + _fade_out->fast_simple_add (len * 1, 0); break; case Slow: - _fade_out.fast_simple_add (len * 0, 1); - _fade_out.fast_simple_add (len * 0.305556, 1); - _fade_out.fast_simple_add (len * 0.548611, 0.991736); - _fade_out.fast_simple_add (len * 0.759259, 0.931129); - _fade_out.fast_simple_add (len * 0.918981, 0.68595); - _fade_out.fast_simple_add (len * 0.976852, 0.22865); - _fade_out.fast_simple_add (len * 1, 0); + _fade_out->fast_simple_add (len * 0, 1); + _fade_out->fast_simple_add (len * 0.305556, 1); + _fade_out->fast_simple_add (len * 0.548611, 0.991736); + _fade_out->fast_simple_add (len * 0.759259, 0.931129); + _fade_out->fast_simple_add (len * 0.918981, 0.68595); + _fade_out->fast_simple_add (len * 0.976852, 0.22865); + _fade_out->fast_simple_add (len * 1, 0); break; case LogB: - _fade_out.fast_simple_add (len * 0, 1); - _fade_out.fast_simple_add (len * 0.080645, 0.730556); - _fade_out.fast_simple_add (len * 0.277778, 0.289256); - _fade_out.fast_simple_add (len * 0.470046, 0.152778); - _fade_out.fast_simple_add (len * 0.695853, 0.0694444); - _fade_out.fast_simple_add (len * 1, 0); + _fade_out->fast_simple_add (len * 0, 1); + _fade_out->fast_simple_add (len * 0.080645, 0.730556); + _fade_out->fast_simple_add (len * 0.277778, 0.289256); + _fade_out->fast_simple_add (len * 0.470046, 0.152778); + _fade_out->fast_simple_add (len * 0.695853, 0.0694444); + _fade_out->fast_simple_add (len * 1, 0); break; case Linear: - _fade_out.fast_simple_add (len * 0, 1); - _fade_out.fast_simple_add (len * 1, 0); + _fade_out->fast_simple_add (len * 0, 1); + _fade_out->fast_simple_add (len * 1, 0); break; } - _fade_out.thaw (); + _fade_out->thaw (); _fade_out_shape = shape; send_change (FadeOutChanged); @@ -795,7 +795,7 @@ AudioRegion::set_fade_out (FadeShape shape, nframes_t len) void AudioRegion::set_fade_in_length (nframes_t len) { - bool changed = _fade_in.extend_to (len); + bool changed = _fade_in->extend_to (len); if (changed) { _flags = Flag (_flags & ~DefaultFadeIn); @@ -806,7 +806,7 @@ AudioRegion::set_fade_in_length (nframes_t len) void AudioRegion::set_fade_out_length (nframes_t len) { - bool changed = _fade_out.extend_to (len); + bool changed = _fade_out->extend_to (len); if (changed) { _flags = Flag (_flags & ~DefaultFadeOut); @@ -848,13 +848,13 @@ AudioRegion::set_fade_out_active (bool yn) bool AudioRegion::fade_in_is_default () const { - return _fade_in_shape == Linear && _fade_in.back()->when == 64; + return _fade_in_shape == Linear && _fade_in->back()->when == 64; } bool AudioRegion::fade_out_is_default () const { - return _fade_out_shape == Linear && _fade_out.back()->when == 64; + return _fade_out_shape == Linear && _fade_out->back()->when == 64; } void @@ -881,11 +881,11 @@ AudioRegion::set_default_fades () void AudioRegion::set_default_envelope () { - _envelope.freeze (); - _envelope.clear (); - _envelope.fast_simple_add (0, 1.0f); - _envelope.fast_simple_add (_length, 1.0f); - _envelope.thaw (); + _envelope->freeze (); + _envelope->clear (); + _envelope->fast_simple_add (0, 1.0f); + _envelope->fast_simple_add (_length, 1.0f); + _envelope->thaw (); } void @@ -895,18 +895,18 @@ AudioRegion::recompute_at_end () based on the the existing curve. */ - _envelope.freeze (); - _envelope.truncate_end (_length); - _envelope.set_max_xval (_length); - _envelope.thaw (); + _envelope->freeze (); + _envelope->truncate_end (_length); + _envelope->set_max_xval (_length); + _envelope->thaw (); - if (_fade_in.back()->when > _length) { - _fade_in.extend_to (_length); + if (_fade_in->back()->when > _length) { + _fade_in->extend_to (_length); send_change (FadeInChanged); } - if (_fade_out.back()->when > _length) { - _fade_out.extend_to (_length); + if (_fade_out->back()->when > _length) { + _fade_out->extend_to (_length); send_change (FadeOutChanged); } } @@ -916,15 +916,15 @@ AudioRegion::recompute_at_start () { /* as above, but the shift was from the front */ - _envelope.truncate_start (_length); + _envelope->truncate_start (_length); - if (_fade_in.back()->when > _length) { - _fade_in.extend_to (_length); + if (_fade_in->back()->when > _length) { + _fade_in->extend_to (_length); send_change (FadeInChanged); } - if (_fade_out.back()->when > _length) { - _fade_out.extend_to (_length); + if (_fade_out->back()->when > _length) { + _fade_out->extend_to (_length); send_change (FadeOutChanged); } } diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 9f3ba6deb6..d7c570ecdf 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -54,7 +54,7 @@ Automatable::old_set_automation_state (const XMLNode& node) uint32_t what; stringstream sstr; - _visible_parameter_automation.clear (); + _visible_controls.clear (); sstr << prop->value(); while (1) { @@ -65,6 +65,8 @@ Automatable::old_set_automation_state (const XMLNode& node) mark_automation_visible (ParamID(PluginAutomation, what), true); } } + + _last_automation_snapshot = 0; return 0; } @@ -89,7 +91,9 @@ Automatable::load_automation (const string& path) Glib::Mutex::Lock lm (_automation_lock); set<ParamID> tosave; - _parameter_automation.clear (); + _controls.clear (); + + _last_automation_snapshot = 0; while (in) { double when; @@ -101,8 +105,8 @@ Automatable::load_automation (const string& path) in >> value; if (!in) goto bad; /* FIXME: this is legacy and only used for plugin inserts? I think? */ - AutomationList* al = automation_list (ParamID(PluginAutomation, port), true); - al->add (when, value); + boost::shared_ptr<AutomationControl> c = control (ParamID(PluginAutomation, port), true); + c->list()->add (when, value); tosave.insert (ParamID(PluginAutomation, port)); } @@ -110,32 +114,35 @@ Automatable::load_automation (const string& path) bad: error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg; - _parameter_automation.clear (); + _controls.clear (); return -1; } void -Automatable::add_automation_parameter(AutomationList* al) +Automatable::add_control(boost::shared_ptr<AutomationControl> ac) { - _parameter_automation[al->param_id()] = al; - - /* let derived classes do whatever they need with this */ - automation_list_creation_callback (al->param_id(), *al); + ParamID param = ac->list()->param_id(); - cerr << _name << ": added parameter " << al->param_id().to_string() << endl; + _controls[param] = ac; + + cerr << _name << ": added parameter " << param.to_string() << endl; // FIXME: sane default behaviour? - _visible_parameter_automation.insert(al->param_id()); - _can_automate_list.insert(al->param_id()); + _visible_controls.insert(param); + _can_automate_list.insert(param); + + // Sync everything (derived classes) up to initial values + auto_state_changed(param); } void Automatable::what_has_automation (set<ParamID>& s) const { Glib::Mutex::Lock lm (_automation_lock); - map<ParamID,AutomationList*>::const_iterator li; + Controls::const_iterator li; - for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) { + // FIXME: correct semantics? + for (li = _controls.begin(); li != _controls.end(); ++li) { s.insert ((*li).first); } } @@ -146,42 +153,45 @@ Automatable::what_has_visible_automation (set<ParamID>& s) const Glib::Mutex::Lock lm (_automation_lock); set<ParamID>::const_iterator li; - for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) { + for (li = _visible_controls.begin(); li != _visible_controls.end(); ++li) { s.insert (*li); } } /** Returns NULL if we don't have an AutomationList for \a parameter. */ -AutomationList* -Automatable::automation_list (ParamID parameter, bool create_if_missing) +boost::shared_ptr<AutomationControl> +Automatable::control (ParamID parameter, bool create_if_missing) { - std::map<ParamID,AutomationList*>::iterator i = _parameter_automation.find(parameter); + Controls::iterator i = _controls.find(parameter); - if (i != _parameter_automation.end()) { + if (i != _controls.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; + assert(parameter.type() != GainAutomation); + boost::shared_ptr<AutomationList> al (new AutomationList ( + parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter))); + boost::shared_ptr<AutomationControl> ac (new AutomationControl(_session, al)); + add_control(ac); + return ac; } else { //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg; - return NULL; + return boost::shared_ptr<AutomationControl>(); } } -const AutomationList* -Automatable::automation_list (ParamID parameter) const +boost::shared_ptr<const AutomationControl> +Automatable::control (ParamID parameter) const { - std::map<ParamID,AutomationList*>::const_iterator i = _parameter_automation.find(parameter); + Controls::const_iterator i = _controls.find(parameter); - if (i != _parameter_automation.end()) { + if (i != _controls.end()) { return i->second; } else { //warning << "AutomationList " << parameter.to_string() << " not found for " << _name << endmsg; - return NULL; + return boost::shared_ptr<AutomationControl>(); } } @@ -196,7 +206,7 @@ Automatable::describe_parameter (ParamID param) else if (param == ParamID(PanAutomation)) return _("Pan"); else if (param.type() == MidiCCAutomation) - return string_compose("MIDI CC %1", param.id()); + return string_compose("CC %1", param.id()); else return param.to_string(); } @@ -211,12 +221,12 @@ void Automatable::mark_automation_visible (ParamID what, bool yn) { if (yn) { - _visible_parameter_automation.insert (what); + _visible_controls.insert (what); } else { set<ParamID>::iterator i; - if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) { - _visible_parameter_automation.erase (i); + if ((i = _visible_controls.find (what)) != _visible_controls.end()) { + _visible_controls.erase (i); } } } @@ -224,24 +234,24 @@ Automatable::mark_automation_visible (ParamID what, bool yn) bool Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const { - map<ParamID,AutomationList*>::const_iterator li; + Controls::const_iterator li; AutomationList::TimeComparator cmp; next_event.when = max_frames; - for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) { + for (li = _controls.begin(); li != _controls.end(); ++li) { AutomationList::const_iterator i; - const AutomationList& alist (*((*li).second)); + boost::shared_ptr<const AutomationList> alist (li->second->list()); ControlEvent cp (now, 0.0f); - for (i = lower_bound (alist.const_begin(), alist.const_end(), &cp, cmp); i != alist.const_end() && (*i)->when < end; ++i) { + for (i = lower_bound (alist->const_begin(), alist->const_end(), &cp, cmp); i != alist->const_end() && (*i)->when < end; ++i) { if ((*i)->when > now) { break; } } - if (i != alist.const_end() && (*i)->when < end) { + if (i != alist->const_end() && (*i)->when < end) { if ((*i)->when < next_event.when) { next_event.when = (*i)->when; @@ -261,8 +271,9 @@ Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param) { Glib::Mutex::Lock lm (_automation_lock); - _parameter_automation.clear (); - _visible_parameter_automation.clear (); + /* Don't clear controls, since some may be special derived Controllable classes */ + + _visible_controls.clear (); XMLNodeList nlist = node.children(); XMLNodeIterator niter; @@ -280,7 +291,7 @@ Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param) ParamID param = (id_prop ? ParamID(id_prop->value()) : legacy_param); - AutomationList* al = new AutomationList(**niter, param); + boost::shared_ptr<AutomationList> al (new AutomationList(**niter, param)); if (!id_prop) { warning << "AutomationList node without automation-id property, " @@ -288,13 +299,19 @@ Automatable::set_automation_state (const XMLNode& node, ParamID legacy_param) al->set_param_id(legacy_param); } - add_automation_parameter(al); + boost::shared_ptr<AutomationControl> existing = control(param); + if (existing) + existing->set_list(al); + else + add_control(boost::shared_ptr<AutomationControl>(new AutomationControl(_session, al))); } else { error << "Expected AutomationList node, got '" << (*niter)->name() << endmsg; } } + _last_automation_snapshot = 0; + return 0; } @@ -304,16 +321,12 @@ Automatable::get_automation_state () Glib::Mutex::Lock lm (_automation_lock); XMLNode* node = new XMLNode (X_("Automation")); - cerr << "'" << _name << "'->get_automation_state, # params = " << _parameter_automation.size() << endl; - - if (_parameter_automation.empty()) { + if (_controls.empty()) { return *node; } - map<ParamID,AutomationList*>::iterator li; - - for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) { - node->add_child_nocopy (li->second->get_state ()); + for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) { + node->add_child_nocopy (li->second->list()->get_state ()); } return *node; @@ -324,10 +337,8 @@ 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(); + for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) + li->second->list()->clear(); } void @@ -335,10 +346,10 @@ Automatable::set_parameter_automation_state (ParamID param, AutoState s) { Glib::Mutex::Lock lm (_automation_lock); - AutomationList* al = automation_list (param, true); + boost::shared_ptr<AutomationControl> c = control (param, true); - if (s != al->automation_state()) { - al->set_automation_state (s); + if (s != c->list()->automation_state()) { + c->list()->set_automation_state (s); _session.set_dirty (); } } @@ -348,10 +359,10 @@ Automatable::get_parameter_automation_state (ParamID param) { Glib::Mutex::Lock lm (_automation_lock); - AutomationList* al = automation_list(param); + boost::shared_ptr<AutomationControl> c = control(param); - if (al) { - return al->automation_state(); + if (c) { + return c->list()->automation_state(); } else { return Off; } @@ -362,10 +373,10 @@ Automatable::set_parameter_automation_style (ParamID param, AutoStyle s) { Glib::Mutex::Lock lm (_automation_lock); - AutomationList* al = automation_list (param, true); + boost::shared_ptr<AutomationControl> c = control(param, true); - if (s != al->automation_style()) { - al->set_automation_style (s); + if (s != c->list()->automation_style()) { + c->list()->set_automation_style (s); _session.set_dirty (); } } @@ -375,10 +386,10 @@ Automatable::get_parameter_automation_style (ParamID param) { Glib::Mutex::Lock lm (_automation_lock); - AutomationList* al = automation_list(param); + boost::shared_ptr<AutomationControl> c = control(param); - if (al) { - return al->automation_style(); + if (c) { + return c->list()->automation_style(); } else { return Absolute; // whatever } @@ -393,14 +404,14 @@ Automatable::protect_automation () for (set<ParamID>::iterator i = automated_params.begin(); i != automated_params.end(); ++i) { - AutomationList* al = automation_list (*i); + boost::shared_ptr<AutomationControl> c = control(*i); - switch (al->automation_state()) { + switch (c->list()->automation_state()) { case Write: - al->set_automation_state (Off); + c->list()->set_automation_state (Off); break; case Touch: - al->set_automation_state (Play); + c->list()->set_automation_state (Play); break; default: break; @@ -408,3 +419,18 @@ Automatable::protect_automation () } } +void +Automatable::automation_snapshot (nframes_t now) +{ + if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) { + + for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) { + if (i->second->list()->automation_write()) { + i->second->list()->rt_add (now, i->second->user_value()); + } + } + + _last_automation_snapshot = now; + } +} + diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc new file mode 100644 index 0000000000..8f8e40a641 --- /dev/null +++ b/libs/ardour/automation_control.cc @@ -0,0 +1,85 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + 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. + +*/ + +#include <iostream> +#include <ardour/automation_control.h> +#include <ardour/session.h> +#include <ardour/automatable.h> + +using namespace std; +using namespace ARDOUR; +using namespace PBD; + + +AutomationControl::AutomationControl(Session& session, boost::shared_ptr<AutomationList> list, string name) + : Controllable((name == "unnamed controllable") ? list->param_id().to_string() : name) + , _session(session) + , _list(list) + , _user_value(list->default_value()) +{ + cerr << "Created AutomationControl " << name << "(" << list->param_id().to_string() << ")" << endl; +} + + +/** Get the currently effective value (ie the one that corresponds to current output) + */ +float +AutomationControl::get_value() const +{ + if (_list->automation_playback()) + return _list->eval(_session.transport_frame()); + else + return _user_value; +} + + +void +AutomationControl::set_value(float value) +{ + _user_value = value; + + if (_session.transport_stopped() && _list->automation_write()) + _list->add(_session.transport_frame(), value); + + Changed(); /* EMIT SIGNAL */ +} + + +/** Get the latest user-set value, which may not equal get_value() when automation + * is playing back, etc. + * + * Automation write/touch works by periodically sampling this value and adding it + * to the AutomationList. + */ +float +AutomationControl::user_value() const +{ + return _user_value; +} + + +void +AutomationControl::set_list(boost::shared_ptr<ARDOUR::AutomationList> list) +{ + _list = list; + _user_value = list->default_value(); + Changed(); /* EMIT SIGNAL */ +} + diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index b620054558..9c1a6126f6 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -1195,8 +1195,6 @@ 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")); @@ -1208,11 +1206,11 @@ AutomationList::state (bool full) 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); + root->add_property ("min_yval", buf); snprintf (buf, sizeof (buf), "%.12g", _max_yval); - root->add_property ("_max_yval", buf); + root->add_property ("max_yval", buf); snprintf (buf, sizeof (buf), "%.12g", _max_xval); - root->add_property ("_max_xval", buf); + root->add_property ("max_xval", buf); if (full) { root->add_property ("state", auto_state_to_string (_state)); @@ -1390,19 +1388,19 @@ AutomationList::set_state (const XMLNode& node) _state = Off; } - if ((prop = node.property (X_("_min_yval"))) != 0) { + if ((prop = node.property (X_("min_yval"))) != 0) { _min_yval = atof (prop->value ()); } else { _min_yval = FLT_MIN; } - if ((prop = node.property (X_("_max_yval"))) != 0) { + if ((prop = node.property (X_("max_yval"))) != 0) { _max_yval = atof (prop->value ()); } else { _max_yval = FLT_MAX; } - if ((prop = node.property (X_("_max_xval"))) != 0) { + if ((prop = node.property (X_("max_xval"))) != 0) { _max_xval = atof (prop->value ()); } else { _max_xval = 0; // means "no limit ; diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index b61a654b25..f04af47f8c 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -62,8 +62,6 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -nframes_t IO::_automation_interval = 0; - const string IO::state_node_name = "IO"; bool IO::connecting_legal = false; bool IO::ports_legal = false; @@ -81,6 +79,7 @@ Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT; others can be imagined. */ +#if 0 static gain_t direct_control_to_gain (double fract) { /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */ /* this maxes at +6dB */ @@ -93,7 +92,7 @@ static double direct_gain_to_control (gain_t gain) { return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0); } - +#endif /** @param default_type The type of port that will be created by ensure_io * and friends if no type is explicitly requested (to avoid breakage). @@ -104,7 +103,6 @@ IO::IO (Session& s, const string& name, : Automatable (s, name), _output_buffers (new BufferSet()), _default_type (default_type), - _gain_control (X_("gaincontrol"), *this), _input_minimum (ChanCount::ZERO), _input_maximum (ChanCount::INFINITE), _output_minimum (ChanCount::ZERO), @@ -135,15 +133,16 @@ 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)); + boost::shared_ptr<AutomationList> gl( + new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0)); - apply_gain_automation = false; - - last_automation_snapshot = 0; + _gain_control = boost::shared_ptr<GainControl>( + new GainControl(X_("gaincontrol"), *this, gl)); - /*_gain_automation_state = Off; - _gain_automation_style = Absolute;*/ + add_control(_gain_control); + apply_gain_automation = false; + { // IO::Meter is emitted from another thread so the // Meter signal must be protected. @@ -154,14 +153,13 @@ IO::IO (Session& s, const string& name, // Connect to our own MoreChannels signal to connect output buffers IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers)); - _session.add_controllable (&_gain_control); + _session.add_controllable (_gain_control); } IO::IO (Session& s, const XMLNode& node, DataType dt) : Automatable (s, "unnamed io"), _output_buffers (new BufferSet()), - _default_type (dt), - _gain_control (X_("gaincontrol"), *this) + _default_type (dt) { _meter = new PeakMeter (_session); @@ -174,6 +172,14 @@ IO::IO (Session& s, const XMLNode& node, DataType dt) _output_bundle = 0; apply_gain_automation = false; + + boost::shared_ptr<AutomationList> gl( + new AutomationList(ParamID(GainAutomation), 0.0, 2.0, 1.0)); + + _gain_control = boost::shared_ptr<GainControl>( + new GainControl(X_("gaincontrol"), *this, gl)); + + add_control(_gain_control); set_state (node); @@ -187,7 +193,7 @@ IO::IO (Session& s, const XMLNode& node, DataType dt) // Connect to our own MoreChannels signal to connect output buffers IO::MoreChannels.connect (mem_fun (*this, &IO::attach_buffers)); - _session.add_controllable (&_gain_control); + _session.add_controllable (_gain_control); } IO::~IO () @@ -1129,8 +1135,8 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src) gain_t IO::effective_gain () const { - if (gain_automation().automation_playback()) { - return _effective_gain; + if (_gain_control->list()->automation_playback()) { + return _gain_control->get_value(); } else { return _desired_gain; } @@ -1272,7 +1278,7 @@ IO::state (bool full_state) } node->add_child_nocopy (_panner->state (full_state)); - node->add_child_nocopy (_gain_control.get_state ()); + node->add_child_nocopy (_gain_control->get_state ()); snprintf (buf, sizeof(buf), "%2.12f", gain()); node->add_property ("gain", buf); @@ -1359,7 +1365,7 @@ IO::set_state (const XMLNode& node) if ((*iter)->name() == X_("controllable")) { if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") { - _gain_control.set_state (**iter); + _gain_control->set_state (**iter); } } } @@ -1396,8 +1402,6 @@ IO::set_state (const XMLNode& node) pending_state_node = new XMLNode (node); } - last_automation_snapshot = 0; - return 0; } @@ -1458,7 +1462,7 @@ IO::load_automation (string path) switch (type) { case 'g': - gain_automation().fast_simple_add (when, value); + _gain_control->list()->fast_simple_add (when, value); break; case 's': @@ -2131,15 +2135,22 @@ IO::output_bundle_configuration_changed () } void -IO::GainControllable::set_value (float val) +IO::GainControl::set_value (float val) { - io.set_gain (direct_control_to_gain (val), this); + // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05)) + if (val > 1.99526231f) + val = 1.99526231f; + + _user_value = val; + _io.set_gain (val, this); + + Changed(); /* EMIT SIGNAL */ } float -IO::GainControllable::get_value (void) const +IO::GainControl::get_value (void) const { - return direct_gain_to_control (io.effective_gain()); + return AutomationControl::get_value(); } void @@ -2193,16 +2204,16 @@ IO::set_parameter_automation_state (ParamID param, AutoState state) { Glib::Mutex::Lock lm (_automation_lock); - ARDOUR::AutomationList& gain_auto = gain_automation(); + boost::shared_ptr<AutomationList> gain_auto = _gain_control->list(); - if (state != gain_auto.automation_state()) { + if (state != gain_auto->automation_state()) { changed = true; - last_automation_snapshot = 0; - gain_auto.set_automation_state (state); + _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); + set_gain (gain_auto->eval (_session.transport_frame()), this); } } } @@ -2229,7 +2240,15 @@ void IO::set_gain (gain_t val, void *src) { // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05)) - if (val>1.99526231f) val=1.99526231f; + if (val > 1.99526231f) + val = 1.99526231f; + + if (src != _gain_control.get()) { + _gain_control->set_value(val); + // bit twisty, this will come back and call us again + // (this keeps control in sync with reality) + return; + } { Glib::Mutex::Lock dm (declick_lock); @@ -2237,17 +2256,11 @@ IO::set_gain (gain_t val, void *src) } if (_session.transport_stopped()) { - _effective_gain = val; _gain = val; } - - gain_changed (src); - _gain_control.Changed (); /* EMIT SIGNAL */ - 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); + if (_session.transport_stopped() && src != 0 && src != this && _gain_control->list()->automation_write()) { + _gain_control->list()->add (_session.transport_frame(), val); } @@ -2258,7 +2271,7 @@ void IO::start_pan_touch (uint32_t which) { if (which < _panner->size()) { - (*_panner)[which]->automation().start_touch(); + (*_panner)[which]->automation()->start_touch(); } } @@ -2266,7 +2279,7 @@ void IO::end_pan_touch (uint32_t which) { if (which < _panner->size()) { - (*_panner)[which]->automation().stop_touch(); + (*_panner)[which]->automation()->stop_touch(); } } @@ -2274,35 +2287,26 @@ IO::end_pan_touch (uint32_t which) void IO::automation_snapshot (nframes_t now) { - if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) { - - ARDOUR::AutomationList& gain_auto = gain_automation(); + Automatable::automation_snapshot (now); - if (gain_auto.automation_write()) { - gain_auto.rt_add (now, gain()); - } - + if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) { _panner->snapshot (now); - - last_automation_snapshot = now; } } void IO::transport_stopped (nframes_t frame) { - ARDOUR::AutomationList& gain_auto = gain_automation(); - - gain_auto.reposition_for_rt_add (frame); + _gain_control->list()->reposition_for_rt_add (frame); - if (gain_auto.automation_state() != Off) { + if (_gain_control->list()->automation_state() != Off) { /* the src=0 condition is a special signal to not propagate automation gain changes into the mix group when locating. */ // FIXME: shouldn't this use Curve? - set_gain (gain_auto.eval (frame), 0); + set_gain (_gain_control->list()->eval (frame), 0); } _panner->transport_stopped (frame); diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 9114f689b2..6386714c16 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -596,7 +596,7 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, nframes_t // XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX // Write into playback buffer here, and whatnot? - cerr << "MDS FIXME: collect playback" << endl; + //cerr << "MDS FIXME: collect playback" << endl; } @@ -1498,9 +1498,8 @@ MidiDiskstream::get_playback(MidiBuffer& dst, nframes_t start, nframes_t end) dst.clear(); assert(dst.size() == 0); - // I think this happens with reverse varispeed? maybe? + // Reverse. ... We just don't do reverse, ok? Back off. if (end <= start) { - cerr << "MDS: Reverse? Skipping" << endl; return; } diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 71a2735606..a10161bc72 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -193,8 +193,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base) child = *niter; if (child->name() == X_("recenable")) { - _rec_enable_control.set_state (*child); - _session.add_controllable (&_rec_enable_control); + _rec_enable_control->set_state (*child); + _session.add_controllable (_rec_enable_control); } } @@ -249,7 +249,7 @@ MidiTrack::state(bool full_state) _diskstream->id().print (buf, sizeof(buf)); root.add_property ("diskstream-id", buf); - root.add_child_nocopy (_rec_enable_control.get_state()); + root.add_child_nocopy (_rec_enable_control->get_state()); return root; } @@ -426,6 +426,15 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, { int dret; boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream(); + + { + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (lm.locked()) { + // automation snapshot can also be called from the non-rt context + // and it uses the redirect list, so we take the lock out here + automation_snapshot (start_frame); + } + } if (n_outputs().n_total() == 0 && _processors.empty()) { return 0; diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index d5a238e253..fa05ff4451 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -71,11 +71,11 @@ static double direct_pan_to_control (pan_t val) { StreamPanner::StreamPanner (Panner& p) : parent (p), - _control (X_("panner"), *this) + _control (new PanControllable(X_("panner"), *this)) { _muted = false; - parent.session().add_controllable (&_control); + parent.session().add_controllable (_control); x = 0.5; y = 0.5; @@ -132,7 +132,7 @@ StreamPanner::set_position (float xpos, bool link_call) x = xpos; update (); Changed (); - _control.Changed (); + _control->Changed (); } } @@ -190,7 +190,7 @@ StreamPanner::add_state (XMLNode& node) /*---------------------------------------------------------------------- */ BaseStereoPanner::BaseStereoPanner (Panner& p) - : StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5) + : StreamPanner (p), _automation (new AutomationList(ParamID(PanAutomation), 0.0, 1.0, 0.5)) { } @@ -201,36 +201,36 @@ BaseStereoPanner::~BaseStereoPanner () void BaseStereoPanner::snapshot (nframes_t now) { - if (_automation.automation_state() == Write || _automation.automation_state() == Touch) { - _automation.rt_add (now, x); + if (_automation->automation_state() == Write || _automation->automation_state() == Touch) { + _automation->rt_add (now, x); } } void BaseStereoPanner::transport_stopped (nframes_t frame) { - _automation.reposition_for_rt_add (frame); + _automation->reposition_for_rt_add (frame); - if (_automation.automation_state() != Off) { - set_position (_automation.eval (frame)); + if (_automation->automation_state() != Off) { + set_position (_automation->eval (frame)); } } void BaseStereoPanner::set_automation_style (AutoStyle style) { - _automation.set_automation_style (style); + _automation->set_automation_style (style); } void BaseStereoPanner::set_automation_state (AutoState state) { - if (state != _automation.automation_state()) { + if (state != _automation->automation_state()) { - _automation.set_automation_state (state); + _automation->set_automation_state (state); if (state != Off) { - set_position (_automation.eval (parent.session().transport_frame())); + set_position (_automation->eval (parent.session().transport_frame())); } } } @@ -241,7 +241,7 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) char line[128]; LocaleGuard lg (X_("POSIX")); - _automation.clear (); + _automation->clear (); while (in.getline (line, sizeof (line), '\n')) { nframes_t when; @@ -258,12 +258,12 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) continue; } - _automation.fast_simple_add (when, value); + _automation->fast_simple_add (when, value); } /* now that we are done loading */ - _automation.StateChanged (); + _automation->StateChanged (); return 0; } @@ -438,7 +438,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob /* fetch positional data */ - if (!_automation.curve().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); @@ -518,12 +518,12 @@ EqualPowerStereoPanner::state (bool full_state) root->add_property (X_("type"), EqualPowerStereoPanner::name); XMLNode* autonode = new XMLNode (X_("Automation")); - autonode->add_child_nocopy (_automation.state (full_state)); + autonode->add_child_nocopy (_automation->state (full_state)); root->add_child_nocopy (*autonode); StreamPanner::add_state (*root); - root->add_child_nocopy (_control.get_state ()); + root->add_child_nocopy (_control->get_state ()); return *root; } @@ -546,15 +546,15 @@ EqualPowerStereoPanner::set_state (const XMLNode& node) if ((*iter)->name() == X_("controllable")) { if ((prop = (*iter)->property("name")) != 0 && prop->value() == "panner") { - _control.set_state (**iter); + _control->set_state (**iter); } } else if ((*iter)->name() == X_("Automation")) { - _automation.set_state (*((*iter)->children().front())); + _automation->set_state (*((*iter)->children().front())); - if (_automation.automation_state() != Off) { - set_position (_automation.eval (parent.session().transport_frame())); + if (_automation->automation_state() != Off) { + set_position (_automation->eval (parent.session().transport_frame())); } } } @@ -565,7 +565,7 @@ EqualPowerStereoPanner::set_state (const XMLNode& node) /*----------------------------------------------------------------------*/ Multi2dPanner::Multi2dPanner (Panner& p) - : StreamPanner (p), _automation (ParamID(PanAutomation), 0.0, 1.0, 0.5) // XXX useless + : StreamPanner (p), _automation (new AutomationList(ParamID(PanAutomation), 0.0, 1.0, 0.5)) // XXX useless { update (); } @@ -930,10 +930,10 @@ Panner::reset (uint32_t nouts, uint32_t npans) if (changed || ((left == 0.5) && (right == 0.5))) { front()->set_position (0.0); - front()->automation().reset_default (0.0); + front()->automation()->reset_default (0.0); back()->set_position (1.0); - back()->automation().reset_default (1.0); + back()->automation()->reset_default (1.0); changed = true; } @@ -990,7 +990,7 @@ AutoState Panner::automation_state () const { if (!empty()) { - return front()->automation().automation_state (); + return front()->automation()->automation_state (); } else { return Off; } @@ -1000,7 +1000,7 @@ AutoStyle Panner::automation_style () const { if (!empty()) { - return front()->automation().automation_style (); + return front()->automation()->automation_style (); } else { return Absolute; } @@ -1026,7 +1026,7 @@ void Panner::clear_automation () { for (vector<StreamPanner*>::iterator i = begin(); i != end(); ++i) { - (*i)->automation().clear (); + (*i)->automation()->clear (); } _session.set_dirty (); } @@ -1181,7 +1181,7 @@ bool Panner::touching () const { for (vector<StreamPanner*>::const_iterator i = begin(); i != end(); ++i) { - if ((*i)->automation().touching ()) { + if ((*i)->automation()->touching ()) { return true; } } diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index a842277845..08a8343fbb 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -142,8 +142,6 @@ void PluginInsert::init () { set_automatable (); - - set<uint32_t>::iterator s; } PluginInsert::~PluginInsert () @@ -152,21 +150,15 @@ PluginInsert::~PluginInsert () } void -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 (ParamID which) { if (which.type() != PluginAutomation) return; - AutomationList* alist = automation_list (which); + boost::shared_ptr<AutomationControl> c = control (which); - if (alist && alist->automation_state() != Off) { - _plugins[0]->set_parameter (which.id(), alist->eval (_session.transport_frame())); + if (c && c->list()->automation_state() != Off) { + _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame())); } } @@ -213,12 +205,23 @@ PluginInsert::is_generator() const void PluginInsert::set_automatable () { - set<ParamID> a; - - a = _plugins.front()->automatable (); + set<ParamID> a = _plugins.front()->automatable (); + + Plugin::ParameterDescriptor desc; for (set<ParamID>::iterator i = a.begin(); i != a.end(); ++i) { - can_automate (*i); + if (i->type() == PluginAutomation) { + can_automate (*i); + _plugins.front()->get_parameter_descriptor(i->id(), desc); + boost::shared_ptr<AutomationList> list(new AutomationList( + *i, + (desc.min_unbound ? FLT_MIN : desc.lower), + (desc.max_unbound ? FLT_MAX : desc.upper), + _plugins.front()->default_value(i->id()))); + + add_control(boost::shared_ptr<AutomationControl>( + new AutomationControl(_session, list))); + } } } @@ -276,21 +279,20 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off if (with_auto) { - map<ParamID,AutomationList*>::iterator li; - uint32_t n; + uint32_t n = 0; - for (n = 0, li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li, ++n) { + for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li, ++n) { - AutomationList& alist (*((*li).second)); + boost::shared_ptr<AutomationControl> c = li->second; - if (alist.param_id().type() == PluginAutomation && alist.automation_playback()) { + if (c->list()->param_id().type() == PluginAutomation && c->list()->automation_playback()) { bool valid; - float val = alist.rt_safe_eval (now, valid); + float val = c->list()->rt_safe_eval (now, valid); if (valid) { /* set the first plugin, the others will be set via signals */ - _plugins[0]->set_parameter ((*li).first, val); + _plugins[0]->set_parameter (c->list()->param_id(), val); } } @@ -307,16 +309,15 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off void PluginInsert::automation_snapshot (nframes_t now) { - map<ParamID,AutomationList*>::iterator li; - - for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) { + for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) { - AutomationList *alist = ((*li).second); - if (alist != 0 && alist->param_id().type() == PluginAutomation - && alist->automation_write ()) { + boost::shared_ptr<AutomationControl> c = li->second; + + if (c->list() != 0 && c->list()->param_id().type() == PluginAutomation + && c->list()->automation_write ()) { - float val = _plugins[0]->get_parameter ((*li).first); - alist->rt_add (now, val); + float val = _plugins[0]->get_parameter (c->list()->param_id()); + c->list()->rt_add (now, val); _last_automation_snapshot = now; } } @@ -325,14 +326,14 @@ PluginInsert::automation_snapshot (nframes_t now) void PluginInsert::transport_stopped (nframes_t now) { - 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); + for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) { + + boost::shared_ptr<AutomationControl> c = li->second; + + c->list()->reposition_for_rt_add (now); - if (alist.param_id().type() == PluginAutomation && alist.automation_state() != Off) { - _plugins[0]->set_parameter (li->first, alist.eval (now)); + if (c->list()->param_id().type() == PluginAutomation && c->list()->automation_state() != Off) { + _plugins[0]->set_parameter (li->first, c->list()->eval (now)); } } } @@ -390,8 +391,10 @@ PluginInsert::set_parameter (ParamID param, float val) _plugins[0]->set_parameter (param.id(), val); - if (automation_list (param) && automation_list (param)->automation_write()) { - automation_list (param)->add (_session.audible_frame(), val); + boost::shared_ptr<AutomationControl> c = control (param); + + if (c && c->list()->automation_write()) { + c->list()->add (_session.audible_frame(), val); } _session.set_dirty(); @@ -660,7 +663,7 @@ PluginInsert::state (bool full) child->add_child_nocopy (automation_list (*x).state (full)); autonode->add_child_nocopy (*child); */ - autonode->add_child_nocopy (automation_list (*x)->state (full)); + autonode->add_child_nocopy (control(*x)->list()->state (full)); } node.add_child_nocopy (*autonode); @@ -791,7 +794,7 @@ PluginInsert::set_state(const XMLNode& node) } if (!child->children().empty()) { - automation_list (ParamID(PluginAutomation, port_id), true)->set_state (*child->children().front()); + control (ParamID(PluginAutomation, port_id), true)->list()->set_state (*child->children().front()); } else { if ((cprop = child->property("auto")) != 0) { @@ -799,13 +802,13 @@ PluginInsert::set_state(const XMLNode& node) int x; sscanf (cprop->value().c_str(), "0x%x", &x); - automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (AutoState (x)); + control (ParamID(PluginAutomation, port_id), true)->list()->set_automation_state (AutoState (x)); } else { /* missing */ - automation_list (ParamID(PluginAutomation, port_id), true)->set_automation_state (Off); + control (ParamID(PluginAutomation, port_id), true)->list()->set_automation_state (Off); } } diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index b192eb85c1..76c780f2db 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -157,8 +157,8 @@ Processor::state (bool full_state) XMLNode& automation = Automatable::get_automation_state(); - for (set<ParamID>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) { - if (x != _visible_parameter_automation.begin()) { + for (set<ParamID>::iterator x = _visible_controls.begin(); x != _visible_controls.end(); ++x) { + if (x != _visible_controls.begin()) { sstr << ' '; } sstr << *x; @@ -202,7 +202,7 @@ Processor::set_state (const XMLNode& node) uint32_t what; stringstream sstr; - _visible_parameter_automation.clear (); + _visible_controls.clear (); sstr << prop->value(); while (1) { diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 507d337619..e8e469b446 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -58,16 +58,16 @@ uint32_t Route::order_key_cnt = 0; Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type) : IO (sess, name, input_min, input_max, output_min, output_max, default_type), _flags (flg), - _solo_control (X_("solo"), *this, ToggleControllable::SoloControl), - _mute_control (X_("mute"), *this, ToggleControllable::MuteControl) + _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)), + _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl)) { init (); } Route::Route (Session& sess, const XMLNode& node, DataType default_type) : IO (sess, *node.child ("IO"), default_type), - _solo_control (X_("solo"), *this, ToggleControllable::SoloControl), - _mute_control (X_("mute"), *this, ToggleControllable::MuteControl) + _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)), + _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl)) { init (); _set_state (node, false); @@ -177,33 +177,33 @@ Route::set_gain (gain_t val, void *src) if (_mix_group->is_relative()) { - - gain_t usable_gain = gain(); + gain_t usable_gain = gain(); if (usable_gain < 0.000001f) { - usable_gain=0.000001f; + usable_gain = 0.000001f; } gain_t delta = val; if (delta < 0.000001f) { - delta=0.000001f; + delta = 0.000001f; } delta -= usable_gain; - if (delta == 0.0f) return; + if (delta == 0.0f) + return; gain_t factor = delta / usable_gain; if (factor > 0.0f) { factor = _mix_group->get_max_factor(factor); if (factor == 0.0f) { - gain_changed (src); + _gain_control->Changed(); /* EMIT SIGNAL */ return; } } else { factor = _mix_group->get_min_factor(factor); if (factor == 0.0f) { - gain_changed (src); + _gain_control->Changed(); /* EMIT SIGNAL */ return; } } @@ -726,7 +726,7 @@ Route::set_solo (bool yn, void *src) if (_soloed != yn) { _soloed = yn; solo_changed (src); /* EMIT SIGNAL */ - _solo_control.Changed (); /* EMIT SIGNAL */ + _solo_control->Changed (); /* EMIT SIGNAL */ } } @@ -763,7 +763,7 @@ Route::set_mute (bool yn, void *src) _muted = yn; mute_changed (src); /* EMIT SIGNAL */ - _mute_control.Changed (); /* EMIT SIGNAL */ + _mute_control->Changed (); /* EMIT SIGNAL */ Glib::Mutex::Lock lm (declick_lock); desired_mute_gain = (yn?0.0f:1.0f); @@ -1491,8 +1491,8 @@ Route::state(bool full_state) node->add_property ("order-keys", order_string); node->add_child_nocopy (IO::state (full_state)); - node->add_child_nocopy (_solo_control.get_state ()); - node->add_child_nocopy (_mute_control.get_state ()); + node->add_child_nocopy (_solo_control->get_state ()); + node->add_child_nocopy (_mute_control->get_state ()); XMLNode* remote_control_node = new XMLNode (X_("remote_control")); snprintf (buf, sizeof (buf), "%d", _remote_control_id); @@ -1853,12 +1853,12 @@ Route::_set_state (const XMLNode& node, bool call_base) } else if (child->name() == X_("controllable") && (prop = child->property("name")) != 0) { if (prop->value() == "solo") { - _solo_control.set_state (*child); - _session.add_controllable (&_solo_control); + _solo_control->set_state (*child); + _session.add_controllable (_solo_control); } else if (prop->value() == "mute") { - _mute_control.set_state (*child); - _session.add_controllable (&_mute_control); + _mute_control->set_state (*child); + _session.add_controllable (_mute_control); } } else if (child->name() == X_("remote_control")) { @@ -2038,7 +2038,7 @@ Route::set_control_outs (const vector<string>& ports) _control_outs = 0; } - if (control() || master()) { + if (is_control() || is_master()) { /* no control outs for these two special busses */ return 0; } @@ -2393,10 +2393,9 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nfra if (am.locked() && _session.transport_rolling()) { - 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); + if (_gain_control->list()->automation_playback()) { + apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector ( + start_frame, end_frame, _session.gain_automation_buffer(), nframes); } } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index c40dd6fd7a..d5c2817f54 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -122,7 +122,8 @@ Session::Session (AudioEngine &eng, routes (new RouteList), auditioner ((Auditioner*) 0), _click_io ((IO*) 0), - main_outs (0) + main_outs (0), + _automation_interval (0) { if (!eng.connected()) { throw failed_constructor(); @@ -221,7 +222,8 @@ Session::Session (AudioEngine &eng, _send_smpte_update (false), diskstreams (new DiskstreamList), routes (new RouteList), - main_outs (0) + main_outs (0), + _automation_interval (0) { if (!eng.connected()) { @@ -1267,7 +1269,7 @@ Session::set_frame_rate (nframes_t frames_per_second) sync_time_vars(); - Route::set_automation_interval ((nframes_t) ceil ((double) frames_per_second * 0.25)); + _automation_interval = ((nframes_t) ceil ((double) frames_per_second * 0.25)); // XXX we need some equivalent to this, somehow // SndFileSource::setup_standard_crossfades (frames_per_second); @@ -1504,7 +1506,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (dynamic_cast<MidiTrack*>((*i).get()) != 0) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { n++; channels_used += (*i)->n_inputs().n_midi(); } @@ -1585,7 +1587,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (dynamic_cast<AudioTrack*>((*i).get()) != 0) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { n++; channels_used += (*i)->n_inputs().n_audio(); } @@ -1775,7 +1777,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (dynamic_cast<AudioTrack*>((*i).get()) == 0) { - if (!(*i)->hidden() && (*i)->name() != _("master")) { + if (!(*i)->is_hidden() && (*i)->name() != _("master")) { bus_id++; } } @@ -1892,11 +1894,11 @@ Session::add_routes (RouteList& new_routes, bool save) (*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x)); (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false)); - if ((*x)->master()) { + if ((*x)->is_master()) { _master_out = (*x); } - if ((*x)->control()) { + if ((*x)->is_control()) { _control_out = (*x); } } @@ -3436,7 +3438,7 @@ Session::set_all_solo (bool yn) shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { (*i)->set_solo (yn, this); } } @@ -3450,7 +3452,7 @@ Session::set_all_mute (bool yn) shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { (*i)->set_mute (yn, this); } } diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index dc71a40ca2..44b63e0875 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -101,7 +101,7 @@ Session::no_roll (nframes_t nframes, nframes_t offset) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if ((*i)->hidden()) { + if ((*i)->is_hidden()) { continue; } @@ -140,7 +140,7 @@ Session::process_routes (nframes_t nframes, nframes_t offset) int ret; - if ((*i)->hidden()) { + if ((*i)->is_hidden()) { continue; } @@ -186,7 +186,7 @@ Session::silent_process_routes (nframes_t nframes, nframes_t offset) int ret; - if ((*i)->hidden()) { + if ((*i)->is_hidden()) { continue; } @@ -819,7 +819,7 @@ Session::process_audition (nframes_t nframes) boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { (*i)->silence (nframes, 0); } } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 65c48a2296..2924210e0c 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -939,7 +939,7 @@ Session::state(bool full_state) public_order.sort (cmp); for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { if (full_state) { child->add_child_nocopy ((*i)->get_state()); } else { @@ -2055,7 +2055,7 @@ Session::get_global_route_boolean (bool (Route::*method)(void) const) boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { RouteBooleanState v; v.first =* i; @@ -2076,7 +2076,7 @@ Session::get_global_route_metering () boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { RouteMeterState v; v.first =* i; @@ -2622,7 +2622,7 @@ Session::set_deletion_in_progress () } void -Session::add_controllable (Controllable* c) +Session::add_controllable (boost::shared_ptr<Controllable> c) { /* this adds a controllable to the list managed by the Session. this is a subset of those managed by the Controllable class @@ -2633,6 +2633,8 @@ Session::add_controllable (Controllable* c) Glib::Mutex::Lock lm (controllables_lock); controllables.insert (c); } + +struct null_deleter { void operator()(void const *) const {} }; void Session::remove_controllable (Controllable* c) @@ -2643,14 +2645,15 @@ Session::remove_controllable (Controllable* c) Glib::Mutex::Lock lm (controllables_lock); - Controllables::iterator x = controllables.find (c); + Controllables::iterator x = controllables.find( + boost::shared_ptr<Controllable>(c, null_deleter())); if (x != controllables.end()) { controllables.erase (x); } } -Controllable* +boost::shared_ptr<Controllable> Session::controllable_by_id (const PBD::ID& id) { Glib::Mutex::Lock lm (controllables_lock); @@ -2661,7 +2664,7 @@ Session::controllable_by_id (const PBD::ID& id) } } - return 0; + return boost::shared_ptr<Controllable>(); } void diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 52f6346789..c122989b68 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -363,7 +363,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if (!(*i)->hidden()) { + if (!(*i)->is_hidden()) { (*i)->set_pending_declick (0); } } @@ -1262,7 +1262,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) update_jack = true; } - if (!(*i)->hidden() && ((*i)->active())) { + if (!(*i)->is_hidden() && ((*i)->active())) { _worst_track_latency = max (_worst_track_latency, track_latency); } } diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index dd6d7a2067..052105cc85 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -40,7 +40,7 @@ using namespace PBD; Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type) : Route (sess, name, 1, -1, -1, -1, flag, default_type) - , _rec_enable_control (*this) + , _rec_enable_control (new RecEnableControllable(*this)) { _declickable = true; _freeze_record.state = NoFreeze; @@ -50,7 +50,7 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data Track::Track (Session& sess, const XMLNode& node, DataType default_type) : Route (sess, node) - , _rec_enable_control (*this) + , _rec_enable_control (new RecEnableControllable(*this)) { _freeze_record.state = NoFreeze; _declickable = true; @@ -188,7 +188,7 @@ Track::set_record_enable (bool yn, void *src) set_meter_point (_saved_meter_point, this); } - _rec_enable_control.Changed (); + _rec_enable_control->Changed (); } diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc index c3c15b4281..142d224171 100644 --- a/libs/gtkmm2ext/barcontroller.cc +++ b/libs/gtkmm2ext/barcontroller.cc @@ -349,7 +349,8 @@ BarController::expose (GdkEventExpose* event) char buf[64]; buf[0] = '\0'; - label_callback (buf, 64); + if (label_callback) + label_callback (buf, 64); if (buf[0] != '\0') { diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h index c91f4c8a06..ba2e1f3f7b 100644 --- a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h +++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h @@ -32,7 +32,10 @@ namespace Gtkmm2ext { class BarController : public Gtk::Frame { public: - BarController (Gtk::Adjustment& adj, PBD::Controllable&, sigc::slot<void,char*,unsigned int>); + typedef sigc::slot<void,char*,unsigned int> LabelCallback; + + BarController (Gtk::Adjustment& adj, PBD::Controllable&, LabelCallback lc = LabelCallback()); + virtual ~BarController () {} enum Style { @@ -40,6 +43,7 @@ class BarController : public Gtk::Frame RightToLeft, Line, CenterOut, + TopToBottom, BottomToTop }; @@ -64,7 +68,7 @@ class BarController : public Gtk::Frame Gtk::Adjustment& adjustment; BindingProxy binding_proxy; Gtk::DrawingArea darea; - sigc::slot<void,char*,unsigned int> label_callback; + LabelCallback label_callback; Glib::RefPtr<Pango::Layout> layout; Style _style; bool grabbed; diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index 16b35397cf..5ef28d4549 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -228,9 +228,9 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes() Route & route = **it; if ( route.active() - && !route.master() - && !route.hidden() - && !route.control() + && !route.is_master() + && !route.is_hidden() + && !route.is_control() && remote_ids.find( route.remote_control_id() ) == remote_ids.end() ) { @@ -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().automation_state(); + ARDOUR::AutoState gain_state = rs.route().gain_control()->list()->automation_state(); if ( gain_state == Touch || gain_state == Play ) { notify_gain_changed( &rs ); diff --git a/libs/surfaces/mackie/route_signal.cc b/libs/surfaces/mackie/route_signal.cc index 85c234436a..b01b5e0cf5 100644 --- a/libs/surfaces/mackie/route_signal.cc +++ b/libs/surfaces/mackie/route_signal.cc @@ -20,6 +20,7 @@ #include <ardour/route.h> #include <ardour/track.h> #include <ardour/panner.h> +#include <ardour/types.h> #include "mackie_control_protocol.h" @@ -30,13 +31,13 @@ using namespace Mackie; void RouteSignal::connect() { if ( _strip.has_solo() ) - _solo_changed_connection = _route.solo_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) ); + _solo_changed_connection = _route.solo_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) ); if ( _strip.has_mute() ) - _mute_changed_connection = _route.mute_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) ); + _mute_changed_connection = _route.mute_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) ); if ( _strip.has_gain() ) - _gain_changed_connection = _route.gain_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) ); + _gain_changed_connection = _route.control(ARDOUR::GainAutomation)->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) ); _name_changed_connection = _route.NameChanged.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) ); @@ -48,7 +49,7 @@ void RouteSignal::connect() try { _record_enable_changed_connection = - dynamic_cast<ARDOUR::Track&>( _route ).rec_enable_control().Changed + dynamic_cast<ARDOUR::Track&>( _route ).rec_enable_control()->Changed .connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_record_enable_changed ), this ) ) ; } |