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