summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/automatable.h8
-rw-r--r--libs/ardour/ardour/midi_model.h2
-rw-r--r--libs/ardour/ardour/midi_region.h6
-rw-r--r--libs/ardour/ardour/midi_source.h10
-rw-r--r--libs/ardour/ardour/midi_track.h2
-rw-r--r--libs/ardour/automatable.cc15
-rw-r--r--libs/ardour/midi_region.cc59
-rw-r--r--libs/ardour/midi_source.cc14
8 files changed, 107 insertions, 9 deletions
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index 9b83705b0a..79bbec5199 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -24,6 +24,7 @@
#include <set>
#include <string>
#include <boost/shared_ptr.hpp>
+#include "pbd/signals.h"
#include "evoral/ControlSet.hpp"
#include "ardour/types.h"
@@ -94,6 +95,9 @@ public:
int set_automation_state (const XMLNode&, Evoral::Parameter default_param);
XMLNode& get_automation_state();
+ /** Emitted when the automation state of one of our controls changes */
+ PBD::Signal1<void, Evoral::Parameter> AutomationStateChanged;
+
protected:
Session& _a_session;
@@ -109,6 +113,10 @@ public:
nframes_t _last_automation_snapshot;
static nframes_t _automation_interval;
+
+private:
+ void automation_state_changed (Evoral::Parameter const &);
+ PBD::ScopedConnectionList _control_connections; ///< connections to our controls' signals
};
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index 9b2c66d5f0..f879c201ee 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -146,7 +146,7 @@ public:
InsertMergePolicy insert_merge_policy () const;
void set_insert_merge_policy (InsertMergePolicy);
-
+
protected:
int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index 568638ed21..ac65b86fc3 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -115,6 +115,12 @@ class MidiRegion : public Region
void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
void switch_source(boost::shared_ptr<Source> source);
+ void model_changed ();
+ void model_automation_state_changed (Evoral::Parameter const &);
+
+ std::set<Evoral::Parameter> _filtered_parameters; ///< parameters that we ask our source not to return when reading
+ PBD::ScopedConnection _model_connection;
+ PBD::ScopedConnection _source_connection;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h
index 36c8548e20..0d0b744a95 100644
--- a/libs/ardour/ardour/midi_source.h
+++ b/libs/ardour/ardour/midi_source.h
@@ -63,7 +63,10 @@ class MidiSource : virtual public Source
virtual nframes_t midi_read (Evoral::EventSink<nframes_t>& dst,
sframes_t source_start,
sframes_t start, nframes_t cnt,
- sframes_t stamp_offset, sframes_t negative_stamp_offset, MidiStateTracker*) const;
+ sframes_t stamp_offset,
+ sframes_t negative_stamp_offset,
+ MidiStateTracker*,
+ std::set<Evoral::Parameter> const &) const;
virtual nframes_t midi_write (MidiRingBuffer<nframes_t>& src,
sframes_t source_start,
@@ -111,9 +114,12 @@ class MidiSource : virtual public Source
void set_note_mode(NoteMode mode);
boost::shared_ptr<MidiModel> model() { return _model; }
- void set_model(boost::shared_ptr<MidiModel> m) { _model = m; }
+ void set_model (boost::shared_ptr<MidiModel>);
void drop_model();
+ /** Emitted when a different MidiModel is set */
+ PBD::Signal0<void> ModelChanged;
+
protected:
virtual void flush_midi() = 0;
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index d181bea596..42446da70d 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -66,7 +66,7 @@ public:
/** A control that will send "immediate" events to a MIDI track when twiddled */
struct MidiControl : public AutomationControl {
MidiControl(MidiTrack* route, const Evoral::Parameter& param,
- boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>())
+ boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>())
: AutomationControl (route->session(), param, al)
, _route (route)
{}
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index 3d705b3ea7..1e5b497bf7 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -150,6 +150,16 @@ Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
ControlSet::add_control(ac);
_can_automate_list.insert(param);
auto_state_changed(param); // sync everything up
+
+ /* connect to automation_state_changed so that we can emit a signal when one of our controls'
+ automation state changes
+ */
+ boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl> (ac);
+ if (c) {
+ c->alist()->automation_state_changed.connect_same_thread (
+ _control_connections, boost::bind (&Automatable::automation_state_changed, this, c->parameter())
+ );
+ }
}
void
@@ -469,3 +479,8 @@ Automatable::automation_control (const Evoral::Parameter& id) const
return boost::dynamic_pointer_cast<const AutomationControl>(Evoral::ControlSet::control(id));
}
+void
+Automatable::automation_state_changed (Evoral::Parameter const & p)
+{
+ AutomationStateChanged (p); /* EMIT SIGNAL */
+}
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc
index abb3191463..fe49547bf3 100644
--- a/libs/ardour/midi_region.cc
+++ b/libs/ardour/midi_region.cc
@@ -24,7 +24,6 @@
#include <set>
-
#include <glibmm/thread.h>
#include "pbd/basename.h"
@@ -53,6 +52,8 @@ MidiRegion::MidiRegion (const SourceList& srcs)
: Region (srcs)
{
midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1));
+ midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
+ model_changed ();
assert(_name.val().find("/") == string::npos);
assert(_type == DataType::MIDI);
}
@@ -63,6 +64,8 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t
{
assert(_name.val().find("/") == string::npos);
midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1));
+ midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
+ model_changed ();
}
MidiRegion::~MidiRegion ()
@@ -180,7 +183,8 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<nframes_t>&
to_read, // read duration in frames
output_buffer_position, // the offset in the output buffer
negative_output_buffer_position, // amount to substract from note times
- tracker
+ tracker,
+ _filtered_parameters
) != to_read) {
return 0; /* "read nothing" */
}
@@ -246,14 +250,63 @@ MidiRegion::midi_source (uint32_t n) const
void
MidiRegion::switch_source(boost::shared_ptr<Source> src)
{
+ _source_connection.disconnect ();
+
boost::shared_ptr<MidiSource> msrc = boost::dynamic_pointer_cast<MidiSource>(src);
- if (!msrc)
+ if (!msrc) {
return;
+ }
// MIDI regions have only one source
_sources.clear();
_sources.push_back(msrc);
set_name(msrc->name());
+
+ msrc->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
}
+void
+MidiRegion::model_changed ()
+{
+ /* build list of filtered Parameters, being those whose automation state is not `Play' */
+
+ _filtered_parameters.clear ();
+
+ Automatable::Controls const & c = model()->controls();
+
+ for (Automatable::Controls::const_iterator i = c.begin(); i != c.end(); ++i) {
+ boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
+ assert (ac);
+ if (ac->alist()->automation_state() != Play) {
+ _filtered_parameters.insert (ac->parameter ());
+ }
+ }
+
+ /* watch for changes to controls' AutoState */
+ model()->AutomationStateChanged.connect_same_thread (
+ _model_connection, boost::bind (&MidiRegion::model_automation_state_changed, this, _1)
+ );
+}
+
+void
+MidiRegion::model_automation_state_changed (Evoral::Parameter const & p)
+{
+ /* Update our filtered parameters list after a change to a parameter's AutoState */
+
+ boost::shared_ptr<AutomationControl> ac = model()->automation_control (p);
+ assert (ac);
+
+ if (ac->alist()->automation_state() == Play) {
+ _filtered_parameters.erase (p);
+ } else {
+ _filtered_parameters.insert (p);
+ }
+
+ /* the source will have an iterator into the model, and that iterator will have been set up
+ for a given set of filtered_paramters, so now that we've changed that list we must invalidate
+ the iterator.
+ */
+ Glib::Mutex::Lock lm (midi_source(0)->mutex());
+ midi_source(0)->invalidate ();
+}
diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc
index 94c1a9b811..2e549b6fc6 100644
--- a/libs/ardour/midi_source.cc
+++ b/libs/ardour/midi_source.cc
@@ -142,11 +142,13 @@ MidiSource::invalidate ()
_model_iter.invalidate();
}
+/** @param filtered A set of parameters whose MIDI messages will not be returned */
nframes_t
MidiSource::midi_read (Evoral::EventSink<nframes_t>& dst, sframes_t source_start,
sframes_t start, nframes_t cnt,
sframes_t stamp_offset, sframes_t negative_stamp_offset,
- MidiStateTracker* tracker) const
+ MidiStateTracker* tracker,
+ std::set<Evoral::Parameter> const & filtered) const
{
Glib::Mutex::Lock lm (_lock);
@@ -158,7 +160,7 @@ MidiSource::midi_read (Evoral::EventSink<nframes_t>& dst, sframes_t source_start
// If the cached iterator is invalid, search for the first event past start
if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) {
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("*** %1 search for relevant iterator for %1 / %2\n", _name, source_start, start));
- for (i = _model->begin(); i != _model->end(); ++i) {
+ for (i = _model->begin(0, filtered); i != _model->end(); ++i) {
if (converter.to(i->time()) >= start) {
break;
}
@@ -311,4 +313,12 @@ MidiSource::drop_model ()
{
cerr << name() << " drop model\n";
_model.reset();
+ ModelChanged (); /* EMIT SIGNAL */
+}
+
+void
+MidiSource::set_model (boost::shared_ptr<MidiModel> m)
+{
+ _model = m;
+ ModelChanged (); /* EMIT SIGNAL */
}