summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-09-21 16:17:02 +0000
committerDavid Robillard <d@drobilla.net>2008-09-21 16:17:02 +0000
commite14187aadd574d46c82d8eb0d151b526b84ddcc7 (patch)
treea80073703c5c3f4a68b4d50aee2c14be7cc1e204
parenteec19ca7afde0da57b2a4d9abc6ef847e6924975 (diff)
Display recorded controller data (fix show all/existing automation).
git-svn-id: svn://localhost/ardour2/branches/3.0@3779 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/audio_time_axis.cc2
-rw-r--r--gtk2_ardour/automation_controller.cc10
-rw-r--r--gtk2_ardour/automation_controller.h2
-rw-r--r--gtk2_ardour/automation_line.cc7
-rw-r--r--gtk2_ardour/automation_line.h1
-rw-r--r--gtk2_ardour/automation_region_view.cc6
-rw-r--r--gtk2_ardour/automation_region_view.h1
-rw-r--r--gtk2_ardour/automation_streamview.cc17
-rw-r--r--gtk2_ardour/automation_streamview.h4
-rw-r--r--gtk2_ardour/automation_time_axis.cc37
-rw-r--r--gtk2_ardour/generic_pluginui.cc4
-rw-r--r--gtk2_ardour/midi_region_view.cc6
-rw-r--r--gtk2_ardour/midi_time_axis.cc19
-rw-r--r--gtk2_ardour/route_time_axis.cc4
-rw-r--r--libs/ardour/ardour/audioregion.h14
-rw-r--r--libs/ardour/ardour/automatable.h43
-rw-r--r--libs/ardour/ardour/automation_control.h7
-rw-r--r--libs/ardour/ardour/io.h4
-rw-r--r--libs/ardour/ardour/midi_model.h18
-rw-r--r--libs/ardour/ardour/midi_region.h28
-rw-r--r--libs/ardour/ardour/midi_track.h6
-rw-r--r--libs/ardour/ardour/panner.h2
-rw-r--r--libs/ardour/ardour/processor.h2
-rw-r--r--libs/ardour/ardour/region.h13
-rw-r--r--libs/ardour/audio_track.cc2
-rw-r--r--libs/ardour/audioregion.cc8
-rw-r--r--libs/ardour/automatable.cc88
-rw-r--r--libs/ardour/automation_control.cc14
-rw-r--r--libs/ardour/io.cc16
-rw-r--r--libs/ardour/jack_slave.cc2
-rw-r--r--libs/ardour/midi_model.cc81
-rw-r--r--libs/ardour/midi_playlist.cc4
-rw-r--r--libs/ardour/midi_stretch.cc2
-rw-r--r--libs/ardour/plugin_insert.cc18
-rw-r--r--libs/ardour/processor.cc3
-rw-r--r--libs/ardour/quantize.cc3
-rw-r--r--libs/ardour/region.cc14
-rw-r--r--libs/ardour/route.cc2
-rw-r--r--libs/evoral/evoral/Control.hpp5
-rw-r--r--libs/evoral/evoral/ControlList.hpp7
-rw-r--r--libs/evoral/evoral/ControlSet.hpp29
-rw-r--r--libs/evoral/evoral/Sequence.hpp42
-rw-r--r--libs/evoral/src/Control.cpp15
-rw-r--r--libs/evoral/src/ControlList.cpp4
-rw-r--r--libs/evoral/src/ControlSet.cpp42
-rw-r--r--libs/evoral/src/Sequence.cpp167
46 files changed, 455 insertions, 370 deletions
diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc
index 8c77da3443..51aa299128 100644
--- a/gtk2_ardour/audio_time_axis.cc
+++ b/gtk2_ardour/audio_time_axis.cc
@@ -364,7 +364,7 @@ AudioTimeAxisView::update_pans (bool show)
}
boost::shared_ptr<AutomationTimeAxisView> pan_track(new AutomationTimeAxisView (_session,
- _route, _route/*FIXME*/, pan_control,
+ _route, _route, pan_control,
editor,
*this,
false,
diff --git a/gtk2_ardour/automation_controller.cc b/gtk2_ardour/automation_controller.cc
index 775c12f668..263761dcc5 100644
--- a/gtk2_ardour/automation_controller.cc
+++ b/gtk2_ardour/automation_controller.cc
@@ -63,13 +63,15 @@ AutomationController::~AutomationController()
boost::shared_ptr<AutomationController>
AutomationController::create(
boost::shared_ptr<Automatable> parent,
- boost::shared_ptr<Evoral::ControlList> cl,
+ const Evoral::Parameter& param,
boost::shared_ptr<AutomationControl> ac)
{
- Gtk::Adjustment* adjustment = manage(new Gtk::Adjustment(cl->default_value(), cl->get_min_y(), cl->get_max_y()));
+ Gtk::Adjustment* adjustment = manage(new Gtk::Adjustment(param.normal(), param.min(), param.max()));
if (!ac) {
- PBD::warning << "Creating AutomationController for " << cl->parameter().symbol() << endmsg;
- ac = boost::dynamic_pointer_cast<AutomationControl>(parent->control_factory(cl));
+ PBD::warning << "Creating AutomationController for " << param.symbol() << endmsg;
+ ac = boost::dynamic_pointer_cast<AutomationControl>(parent->control_factory(param));
+ } else {
+ assert(ac->parameter() == param);
}
return boost::shared_ptr<AutomationController>(new AutomationController(ac, adjustment));
}
diff --git a/gtk2_ardour/automation_controller.h b/gtk2_ardour/automation_controller.h
index 0da24b3588..767c4ced00 100644
--- a/gtk2_ardour/automation_controller.h
+++ b/gtk2_ardour/automation_controller.h
@@ -37,7 +37,7 @@ class AutomationController : public Gtkmm2ext::BarController {
public:
static boost::shared_ptr<AutomationController> create(
boost::shared_ptr<ARDOUR::Automatable> parent,
- boost::shared_ptr<Evoral::ControlList> cl,
+ const Evoral::Parameter& param,
boost::shared_ptr<ARDOUR::AutomationControl> ac);
~AutomationController();
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc
index 27da5e5c1f..8754bbc21a 100644
--- a/gtk2_ardour/automation_line.cc
+++ b/gtk2_ardour/automation_line.cc
@@ -1107,6 +1107,13 @@ AutomationLine::change_model_range (AutomationList::iterator start, AutomationLi
}
void
+AutomationLine::set_list(boost::shared_ptr<ARDOUR::AutomationList> list)
+{
+ alist = list;
+ queue_reset();
+}
+
+void
AutomationLine::show_all_control_points ()
{
points_visible = true;
diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h
index 92c012fc82..1123a7b9a4 100644
--- a/gtk2_ardour/automation_line.h
+++ b/gtk2_ardour/automation_line.h
@@ -109,6 +109,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
virtual void view_to_model_y (double&);
virtual void model_to_view_y (double&);
+ void set_list(boost::shared_ptr<ARDOUR::AutomationList> list);
boost::shared_ptr<ARDOUR::AutomationList> the_list() const { return alist; }
void show_all_control_points ();
diff --git a/gtk2_ardour/automation_region_view.cc b/gtk2_ardour/automation_region_view.cc
index c213b3feeb..b581cb9a9d 100644
--- a/gtk2_ardour/automation_region_view.cc
+++ b/gtk2_ardour/automation_region_view.cc
@@ -116,6 +116,12 @@ AutomationRegionView::add_automation_event (GdkEvent* event, nframes_t when, dou
_line->the_list()->add (when, y);
+ boost::shared_ptr<ARDOUR::MidiRegion> mr = boost::dynamic_pointer_cast<ARDOUR::MidiRegion>(_region);
+ if (mr) {
+ cout << "ADD TO LIST: " << _line->the_list().get() << " ON " << _region
+ << " (model " << mr->midi_source(0)->model() << ")" << endl;
+ }
+
XMLNode& after = _line->the_list()->get_state();
view->session().commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(
*_line->the_list(), &before, &after));
diff --git a/gtk2_ardour/automation_region_view.h b/gtk2_ardour/automation_region_view.h
index 33c6a6c7e6..759382b562 100644
--- a/gtk2_ardour/automation_region_view.h
+++ b/gtk2_ardour/automation_region_view.h
@@ -54,6 +54,7 @@ public:
inline AutomationTimeAxisView* automation_view() const
{ return dynamic_cast<AutomationTimeAxisView*>(&trackview); }
+ void set_line(boost::shared_ptr<AutomationLine> line) { _line = line; }
boost::shared_ptr<AutomationLine> line() { return _line; }
// We are a ghost. Meta ghosts? Crazy talk.
diff --git a/gtk2_ardour/automation_streamview.cc b/gtk2_ardour/automation_streamview.cc
index 9bce718fce..024d235c7d 100644
--- a/gtk2_ardour/automation_streamview.cc
+++ b/gtk2_ardour/automation_streamview.cc
@@ -99,11 +99,13 @@ AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region
for (i = region_views.begin(); i != region_views.end(); ++i) {
if ((*i)->region() == region) {
- /* great. we already have a MidiRegionView for this Region. use it again. */
+ /* great. we already have an AutomationRegionView for this Region. use it again. */
+ AutomationRegionView* arv = dynamic_cast<AutomationRegionView*>(*i);;
+ arv->line()->set_list (list);
(*i)->set_valid (true);
(*i)->enable_display(wfd);
- display_region(dynamic_cast<AutomationRegionView*>(*i));
+ display_region(arv);
return NULL;
}
@@ -140,6 +142,17 @@ AutomationStreamView::display_region(AutomationRegionView* region_view)
}
void
+AutomationStreamView::set_automation_state (AutoState state)
+{
+ std::list<RegionView *>::iterator i;
+ for (i = region_views.begin(); i != region_views.end(); ++i) {
+ boost::shared_ptr<AutomationLine> line = ((AutomationRegionView*)(*i))->line();
+ if (line && line->the_list())
+ line->the_list()->set_automation_state (state);
+ }
+}
+
+void
AutomationStreamView::redisplay_diskstream ()
{
list<RegionView *>::iterator i, tmp;
diff --git a/gtk2_ardour/automation_streamview.h b/gtk2_ardour/automation_streamview.h
index 5eebfaf28d..4188e7e983 100644
--- a/gtk2_ardour/automation_streamview.h
+++ b/gtk2_ardour/automation_streamview.h
@@ -45,9 +45,7 @@ class AutomationStreamView : public StreamView
AutomationStreamView (AutomationTimeAxisView& tv);
~AutomationStreamView ();
- void set_selected_regionviews (RegionSelection&);
- void get_selectables (jack_nframes_t start, jack_nframes_t end, list<Selectable* >&);
- void get_inverted_selectables (Selection&, list<Selectable* >& results);
+ void set_automation_state (ARDOUR::AutoState state);
void redisplay_diskstream ();
diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc
index daf0a01b95..76ef196b52 100644
--- a/gtk2_ardour/automation_time_axis.cc
+++ b/gtk2_ardour/automation_time_axis.cc
@@ -49,17 +49,21 @@ Pango::FontDescription* AutomationTimeAxisView::name_font = 0;
bool AutomationTimeAxisView::have_name_font = false;
const string AutomationTimeAxisView::state_node_name = "AutomationChild";
+/** \a a the automatable object this time axis is to display data for.
+ * For route/track automation (e.g. gain) pass the route for both \r and \a.
+ * For route child (e.g. plugin) automation, pass the child for \a.
+ * For region automation (e.g. MIDI CC), pass null for \a.
+ */
AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
PublicEditor& e, TimeAxisView& parent, bool show_regions,
ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
-
: AxisView (s),
TimeAxisView (s, e, &parent, canvas),
_route (r),
_control (c),
_automatable (a),
- _controller(AutomationController::create(a, c->list(), c)),
+ _controller(AutomationController::create(a, c->parameter(), c)),
_base_rect (0),
_view (show_regions ? new AutomationStreamView(*this) : NULL),
_name (nom),
@@ -238,14 +242,14 @@ AutomationTimeAxisView::auto_clicked ()
automation_menu->set_name ("ArdourContextMenu");
MenuList& items (automation_menu->items());
- items.push_back (MenuElem (_("Manual"),
- bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
- items.push_back (MenuElem (_("Play"),
- bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
- items.push_back (MenuElem (_("Write"),
- bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
- items.push_back (MenuElem (_("Touch"),
- bind (mem_fun(*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
+ items.push_back (MenuElem (_("Manual"), bind (mem_fun(*this,
+ &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
+ items.push_back (MenuElem (_("Play"), bind (mem_fun(*this,
+ &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
+ items.push_back (MenuElem (_("Write"), bind (mem_fun(*this,
+ &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
+ items.push_back (MenuElem (_("Touch"), bind (mem_fun(*this,
+ &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
}
automation_menu->popup (1, gtk_get_current_event_time());
@@ -255,15 +259,14 @@ void
AutomationTimeAxisView::set_automation_state (AutoState state)
{
if (!ignore_state_request) {
- if (_route == _automatable) { // FIXME: ew
- _route->set_parameter_automation_state (
- _control->parameter(),
- state);
+ if (_route == _automatable) { // This is a time axis for route (not region) automation
+ _route->set_parameter_automation_state (_control->parameter(), state);
}
- _control->alist()->set_automation_state(state);
-
+ if (_control->list())
+ _control->alist()->set_automation_state(state);
}
+ _view->set_automation_state (state);
}
void
@@ -278,7 +281,7 @@ AutomationTimeAxisView::automation_state_changed ()
} else {
state = _control->alist()->automation_state ();
}
-
+
switch (state & (Off|Play|Touch|Write)) {
case Off:
auto_button.set_label (_("Manual"));
diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc
index 34ab571c8c..c77f7e7d74 100644
--- a/gtk2_ardour/generic_pluginui.cc
+++ b/gtk2_ardour/generic_pluginui.cc
@@ -211,7 +211,7 @@ GenericPluginUI::build ()
boost::shared_ptr<ARDOUR::AutomationControl> c
= boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
- insert->control(Parameter(PluginAutomation, i)));
+ insert->data().control(Parameter(PluginAutomation, i)));
if ((cui = build_control_ui (i, c)) == 0) {
error << string_compose(_("Plugin Editor: could not build control element for port %1"), i) << endmsg;
@@ -462,7 +462,7 @@ GenericPluginUI::build_control_ui (guint32 port_index, boost::shared_ptr<Automat
/* create the controller */
- control_ui->controller = AutomationController::create(insert, mcontrol->list(), mcontrol);
+ control_ui->controller = AutomationController::create(insert, mcontrol->parameter(), mcontrol);
/* XXX this code is not right yet, because it doesn't handle
the absence of bounds in any sensible fashion.
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 3184bd104b..bfd23f900e 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -403,7 +403,7 @@ MidiRegionView::create_note_at(double x, double y, double duration)
MidiModel::DeltaCommand* cmd = _model->new_delta_command("add note");
cmd->add(new_note);
- _model->apply_command(cmd);
+ _model->apply_command(trackview.session(), cmd);
}
@@ -474,8 +474,8 @@ MidiRegionView::apply_command()
_marked_for_selection.insert((*i)->note());
}
- _model->apply_command(_delta_command);
- _delta_command = NULL;
+ _model->apply_command(trackview.session(), _delta_command);
+ _delta_command = NULL;
midi_view()->midi_track()->diskstream()->playlist_modified();
_marked_for_selection.clear();
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 500b81cb01..b8f5da2ed9 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -293,8 +293,9 @@ MidiTimeAxisView::show_all_automation ()
const set<Parameter> params = midi_track()->midi_diskstream()->
midi_playlist()->contained_automation();
- for (set<Parameter>::const_iterator i = params.begin(); i != params.end(); ++i)
+ for (set<Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
create_automation_child(*i, true);
+ }
}
RouteTimeAxisView::show_all_automation ();
@@ -307,8 +308,9 @@ MidiTimeAxisView::show_existing_automation ()
const set<Parameter> params = midi_track()->midi_diskstream()->
midi_playlist()->contained_automation();
- for (set<Parameter>::const_iterator i = params.begin(); i != params.end(); ++i)
+ for (set<Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
create_automation_child(*i, true);
+ }
}
RouteTimeAxisView::show_existing_automation ();
@@ -344,24 +346,23 @@ MidiTimeAxisView::create_automation_child (Parameter param, bool show)
param.type() == MidiChannelAftertouchAutomation
) {
- /* FIXME: don't create AutomationList for track itself
- * (not actually needed or used, since the automation is region-ey) */
-
+ /* These controllers are region "automation", so we do not create
+ * an AutomationList/Line for the track */
+
AutomationTracks::iterator existing = _automation_tracks.find(param);
if (existing != _automation_tracks.end())
return;
boost::shared_ptr<AutomationControl> c
- = boost::dynamic_pointer_cast<AutomationControl>(_route->control(param));
+ = boost::dynamic_pointer_cast<AutomationControl>(_route->data().control(param));
if (!c) {
- boost::shared_ptr<AutomationList> al(new ARDOUR::AutomationList(param));
- c = boost::dynamic_pointer_cast<AutomationControl>(_route->control_factory(al));
+ c = boost::dynamic_pointer_cast<AutomationControl>(_route->control_factory(param));
_route->add_control(c);
}
boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
- _route, _route, c,
+ _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
editor,
*this,
true,
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 2eceeb4974..6d6188c146 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -1619,7 +1619,7 @@ RouteTimeAxisView::show_existing_automation ()
for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
+ if ((*ii)->view != 0 && (*i)->processor->data().control((*ii)->what)->list()->size() > 0) {
(*ii)->menu_item->set_active (true);
}
}
@@ -1765,7 +1765,7 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor>
snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
boost::shared_ptr<AutomationControl> control
- = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
+ = boost::dynamic_pointer_cast<AutomationControl>(processor->data().control(what, true));
pan->view = boost::shared_ptr<AutomationTimeAxisView>(
new AutomationTimeAxisView (_session, _route, processor, control,
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()) {
diff --git a/libs/evoral/evoral/Control.hpp b/libs/evoral/evoral/Control.hpp
index 15d50fcdca..01dc2eebed 100644
--- a/libs/evoral/evoral/Control.hpp
+++ b/libs/evoral/evoral/Control.hpp
@@ -34,7 +34,7 @@ class Transport;
class Control
{
public:
- Control(boost::shared_ptr<ControlList>);
+ Control(const Parameter& parameter, boost::shared_ptr<ControlList>);
virtual ~Control() {}
void set_value(float val, bool to_list=false, nframes_t frame=0);
@@ -46,9 +46,10 @@ public:
boost::shared_ptr<ControlList> list() { return _list; }
boost::shared_ptr<const ControlList> list() const { return _list; }
- const Parameter& parameter() const;
+ inline const Parameter& parameter() const { return _parameter; }
protected:
+ Parameter _parameter;
boost::shared_ptr<ControlList> _list;
float _user_value;
};
diff --git a/libs/evoral/evoral/ControlList.hpp b/libs/evoral/evoral/ControlList.hpp
index 1b2b46b10b..36799300fe 100644
--- a/libs/evoral/evoral/ControlList.hpp
+++ b/libs/evoral/evoral/ControlList.hpp
@@ -84,13 +84,12 @@ public:
typedef EventList::const_iterator const_iterator;
ControlList (const Parameter& id);
- //ControlList (const XMLNode&, Parameter id);
+ ControlList (const ControlList&);
+ ControlList (const ControlList&, double start, double end);
virtual ~ControlList();
virtual boost::shared_ptr<ControlList> create(Parameter id);
-
- ControlList (const ControlList&);
- ControlList (const ControlList&, double start, double end);
+
ControlList& operator= (const ControlList&);
bool operator== (const ControlList&);
diff --git a/libs/evoral/evoral/ControlSet.hpp b/libs/evoral/evoral/ControlSet.hpp
index 73fa5554e6..1b5edb92ac 100644
--- a/libs/evoral/evoral/ControlSet.hpp
+++ b/libs/evoral/evoral/ControlSet.hpp
@@ -22,6 +22,7 @@
#include <set>
#include <map>
#include <boost/shared_ptr.hpp>
+#include <boost/utility.hpp>
#include <glibmm/thread.h>
#include <evoral/types.hpp>
#include <evoral/Parameter.hpp>
@@ -32,27 +33,32 @@ class Control;
class ControlList;
class ControlEvent;
-class ControlSet {
+class ControlSet : public boost::noncopyable {
public:
ControlSet();
virtual ~ControlSet() {}
-
- virtual boost::shared_ptr<Control> control(const Parameter& id, bool create_if_missing=false);
- virtual boost::shared_ptr<const Control> control(const Parameter& id) const;
- virtual boost::shared_ptr<Control> control_factory(boost::shared_ptr<ControlList> list) const;
- virtual boost::shared_ptr<ControlList> control_list_factory(const Parameter& param) const;
+ virtual boost::shared_ptr<Evoral::Control>
+ control_factory(const Evoral::Parameter& id) = 0;
+ boost::shared_ptr<Control>
+ control (const Parameter& id, bool create_if_missing=false);
+
+ inline boost::shared_ptr<const Control>
+ control (const Parameter& id) const {
+ const Controls::const_iterator i = _controls.find(id);
+ return (i != _controls.end() ? i->second : boost::shared_ptr<Control>());
+ }
+
typedef std::map< Parameter, boost::shared_ptr<Control> > Controls;
- Controls& controls() { return _controls; }
- const Controls& controls() const { return _controls; }
+ inline Controls& controls() { return _controls; }
+ inline const Controls& controls() const { return _controls; }
virtual void add_control(boost::shared_ptr<Control>);
- virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
+ bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
- virtual float default_parameter_value(const Parameter& param) { return 1.0f; }
-
+ virtual bool empty() const { return _controls.size() == 0; }
virtual void clear();
void what_has_data(std::set<Parameter>&) const;
@@ -64,6 +70,7 @@ protected:
Controls _controls;
};
+
} // namespace Evoral
#endif // EVORAL_CONTROLLABLE_HPP
diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp
index 10a61704ed..73ddaca21b 100644
--- a/libs/evoral/evoral/Sequence.hpp
+++ b/libs/evoral/evoral/Sequence.hpp
@@ -25,7 +25,6 @@
#include <map>
#include <utility>
#include <boost/shared_ptr.hpp>
-#include <boost/utility.hpp>
#include <glibmm/thread.h>
#include <evoral/types.hpp>
#include <evoral/Note.hpp>
@@ -39,6 +38,7 @@ class Note;
class Event;
class ControlList;
+
/** This class keeps track of the current x and y for a control
*/
class ControlIterator {
@@ -59,12 +59,13 @@ public:
/** This is a higher level view of events, with separate representations for
* notes (instead of just unassociated note on/off events) and controller data.
- * Controller data is represented as a list of time-stamped float values.
- */
-class Sequence : public boost::noncopyable, virtual public ControlSet {
+ * Controller data is represented as a list of time-stamped float values. */
+class Sequence : virtual public ControlSet {
public:
- Sequence(size_t size);
+ Sequence(size_t size=0);
+ bool read_locked() { return _read_iter.locked(); }
+
void write_lock();
void write_unlock();
@@ -92,10 +93,10 @@ public:
inline const boost::shared_ptr<Note> note_at(unsigned i) { return _notes[i]; }
inline size_t n_notes() const { return _notes.size(); }
- inline bool empty() const { return _notes.size() == 0 && _controls.size() == 0; }
+ inline bool empty() const { return _notes.size() == 0 && ControlSet::empty(); }
- inline static bool note_time_comparator(const boost::shared_ptr<const Note> a,
- const boost::shared_ptr<const Note> b) {
+ inline static bool note_time_comparator(const boost::shared_ptr<const Note>& a,
+ const boost::shared_ptr<const Note>& b) {
return a->time() < b->time();
}
@@ -117,6 +118,7 @@ public:
const_iterator(const Sequence& seq, double t);
~const_iterator();
+ inline bool valid() const { return !_is_end && _event; }
inline bool locked() const { return _locked; }
const Event& operator*() const { return *_event; }
@@ -149,28 +151,28 @@ public:
std::vector<ControlIterator>::iterator _control_iter;
};
- const_iterator begin() const { return const_iterator(*this, 0); }
- const const_iterator& end() const { return _end_iter; }
+ const_iterator begin(double t=0) const { return const_iterator(*this, t); }
+ const const_iterator& end() const { return _end_iter; }
+ void read_seek(double t) { _read_iter = begin(t); }
+ double read_time() const { return _read_iter.valid() ? _read_iter->time() : 0.0; }
+
bool control_to_midi_event(boost::shared_ptr<Event>& ev,
const ControlIterator& iter) const;
- typedef std::map< Parameter, boost::shared_ptr<Control> > Controls;
- Controls& controls() { return _controls; }
- const Controls& controls() const { return _controls; }
-
bool edited() const { return _edited; }
void set_edited(bool yn) { _edited = yn; }
+
+#ifndef NDEBUG
+ bool is_sorted() const;
+#endif
-protected:
void add_note_unlocked(const boost::shared_ptr<Note> note);
void remove_note_unlocked(const boost::shared_ptr<const Note> note);
+protected:
mutable const_iterator _read_iter;
bool _edited;
-#ifndef NDEBUG
- bool is_sorted() const;
-#endif
private:
friend class const_iterator;
@@ -182,7 +184,6 @@ private:
mutable Glib::RWLock _lock;
Notes _notes;
- Controls _controls;
typedef std::vector<size_t> WriteNotes;
WriteNotes _write_notes[16];
@@ -197,7 +198,7 @@ private:
/** FIXME: Make fully dynamic, map to URIs */
enum EventTypes {
- midi_cc_type=1,
+ midi_cc_type=0x20, // FIXME FIXME FIXME eeww
midi_pc_type,
midi_pb_type,
midi_ca_type
@@ -209,6 +210,7 @@ private:
ActiveNotes;
};
+
} // namespace Evoral
#endif // EVORAL_SEQUENCE_HPP
diff --git a/libs/evoral/src/Control.cpp b/libs/evoral/src/Control.cpp
index d23f6c3c9a..75b038f1d4 100644
--- a/libs/evoral/src/Control.cpp
+++ b/libs/evoral/src/Control.cpp
@@ -24,9 +24,10 @@ namespace Evoral {
Parameter::TypeMetadata Parameter::_type_metadata;
-Control::Control(boost::shared_ptr<ControlList> list)
- : _list(list)
- , _user_value(list->default_value())
+Control::Control(const Parameter& parameter, boost::shared_ptr<ControlList> list)
+ : _parameter(parameter)
+ , _list(list)
+ , _user_value(list ? list->default_value() : parameter.normal())
{
}
@@ -70,14 +71,6 @@ void
Control::set_list(boost::shared_ptr<ControlList> list)
{
_list = list;
- _user_value = list->default_value();
-}
-
-
-const Parameter&
-Control::parameter() const
-{
- return _list->parameter();
}
} // namespace Evoral
diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp
index 62c49a97e6..fd0a2e52bd 100644
--- a/libs/evoral/src/ControlList.cpp
+++ b/libs/evoral/src/ControlList.cpp
@@ -109,7 +109,6 @@ ControlList::~ControlList()
delete (*x);
}
}
-
boost::shared_ptr<ControlList>
ControlList::create(Parameter id)
@@ -117,7 +116,6 @@ ControlList::create(Parameter id)
return boost::shared_ptr<ControlList>(new ControlList(id));
}
-
bool
ControlList::operator== (const ControlList& other)
{
@@ -205,7 +203,7 @@ ControlList::reposition_for_rt_add (double when)
void
ControlList::rt_add (double when, double value)
{
- // cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
+ cerr << "RT: alist " << this << " add " << value << " @ " << when << endl;
{
Glib::Mutex::Lock lm (_lock);
diff --git a/libs/evoral/src/ControlSet.cpp b/libs/evoral/src/ControlSet.cpp
index 5aacff598d..837810c727 100644
--- a/libs/evoral/src/ControlSet.cpp
+++ b/libs/evoral/src/ControlSet.cpp
@@ -26,6 +26,7 @@ using namespace std;
namespace Evoral {
+
ControlSet::ControlSet()
{
}
@@ -40,17 +41,14 @@ void
ControlSet::what_has_data (set<Parameter>& s) const
{
Glib::Mutex::Lock lm (_control_lock);
- Controls::const_iterator li;
-
- // FIXME: correct semantics?
- for (li = _controls.begin(); li != _controls.end(); ++li) {
- s.insert ((*li).first);
+ for (Controls::const_iterator li = _controls.begin(); li != _controls.end(); ++li) {
+ s.insert(li->first);
}
}
-/** If \a create_if_missing is true, a control list will be created and returned
- * if one does not already exists. Otherwise NULL will be returned if a control list
- * for \a parameter does not exist.
+/** If a control for the given parameter does not exist and \a create_if_missing is true,
+ * a control will be created, added to this set, and returned.
+ * If \a create_if_missing is false this function may return null.
*/
boost::shared_ptr<Control>
ControlSet::control (const Parameter& parameter, bool create_if_missing)
@@ -61,8 +59,7 @@ ControlSet::control (const Parameter& parameter, bool create_if_missing)
return i->second;
} else if (create_if_missing) {
- boost::shared_ptr<ControlList> al (control_list_factory(parameter));
- boost::shared_ptr<Control> ac(control_factory(al));
+ boost::shared_ptr<Control> ac(control_factory(parameter));
add_control(ac);
return ac;
@@ -72,19 +69,6 @@ ControlSet::control (const Parameter& parameter, bool create_if_missing)
}
}
-boost::shared_ptr<const Control>
-ControlSet::control (const Parameter& parameter) const
-{
- Controls::const_iterator i = _controls.find(parameter);
-
- if (i != _controls.end()) {
- return i->second;
- } else {
- //warning << "ControlList " << parameter.to_string() << " not found for " << _name << endmsg;
- return boost::shared_ptr<Control>();
- }
-}
-
bool
ControlSet::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
{
@@ -122,18 +106,6 @@ ControlSet::clear ()
for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li)
li->second->list()->clear();
}
-
-boost::shared_ptr<Control>
-ControlSet::control_factory(boost::shared_ptr<ControlList> list) const
-{
- return boost::shared_ptr<Control>(new Control(list));
-}
-
-boost::shared_ptr<ControlList>
-ControlSet::control_list_factory(const Parameter& param) const
-{
- return boost::shared_ptr<ControlList>(new ControlList(param));
-}
} // namespace Evoral
diff --git a/libs/evoral/src/Sequence.cpp b/libs/evoral/src/Sequence.cpp
index fecc37be29..9e073699d9 100644
--- a/libs/evoral/src/Sequence.cpp
+++ b/libs/evoral/src/Sequence.cpp
@@ -52,6 +52,16 @@ void Sequence::read_unlock() const {
_lock.reader_unlock();
}
+struct null_ostream : public std::ostream {
+ null_ostream(): std::ios(0), std::ostream(0) {}
+};
+static null_ostream nullout;
+
+//static ostream& debugout = cout;
+//static ostream& errorout = cerr;
+static ostream& debugout = nullout;
+static ostream& errorout = nullout;
+
// Read iterator (const_iterator)
Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
@@ -59,7 +69,7 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
, _is_end( (t == DBL_MAX) || seq.empty() )
, _locked( !_is_end )
{
- //cerr << "Created MIDI iterator @ " << t << " (is end: " << _is_end << ")" << endl;
+ debugout << "Created Iterator @ " << t << " (is end: " << _is_end << ")" << endl;
if (_is_end) {
return;
@@ -78,30 +88,31 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
ControlIterator earliest_control(boost::shared_ptr<ControlList>(), DBL_MAX, 0.0);
- _control_iters.reserve(seq.controls().size());
+ _control_iters.reserve(seq._controls.size());
// find the earliest control event available
- for (Controls::const_iterator i = seq.controls().begin(); i != seq.controls().end(); ++i) {
+ for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
+ debugout << "Iterator: control: " << i->first.symbol() << endl;
double x, y;
bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
if (!ret) {
- //cerr << "MIDI Iterator: CC " << i->first.id() << " (size " << i->second->list()->size()
- // << ") has no events past " << t << endl;
+ debugout << "Iterator: CC " << i->first.id() << " (size " << i->second->list()->size()
+ << ") has no events past " << t << endl;
continue;
}
assert(x >= 0);
- if (y < i->first.min() || y > i->first.max()) {
- cerr << "ERROR: Controller (" << i->first.type() << ") value '" << y
- << "' out of range [" << i->first.min() << "," << i->first.max()
+ /*if (y < i->first.min() || y > i->first.max()) {
+ errorout << "ERROR: Controller " << i->first.symbol() << " value " << y
+ << " out of range [" << i->first.min() << "," << i->first.max()
<< "], event ignored" << endl;
continue;
- }
+ }*/
const ControlIterator new_iter(i->second->list(), x, y);
- //cerr << "MIDI Iterator: CC " << i->first.id() << " added (" << x << ", " << y << ")" << endl;
+ debugout << "Iterator: CC " << i->first.id() << " added (" << x << ", " << y << ")" << endl;
_control_iters.push_back(new_iter);
// if the x of the current control is less than earliest_control
@@ -137,7 +148,7 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
}
if ( (! _event.get()) || _event->size() == 0) {
- //cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
+ debugout << "New iterator @ " << t << " is at end." << endl;
_is_end = true;
// eliminate possible race condition here (ugly)
@@ -148,7 +159,8 @@ Sequence::const_iterator::const_iterator(const Sequence& seq, double t)
_locked = false;
}
} else {
- //printf("New MIDI Iterator = %X @ %lf\n", _event->type(), _event->time());
+ debugout << "New Iterator = " << hex << _event->type();
+ debugout << " @ " << _event->time() << endl;
}
assert(_is_end || (_event->buffer() && _event->buffer()[0] != '\0'));
@@ -161,7 +173,8 @@ Sequence::const_iterator::~const_iterator()
}
}
-const Sequence::const_iterator& Sequence::const_iterator::operator++()
+const
+Sequence::const_iterator& Sequence::const_iterator::operator++()
{
if (_is_end) {
throw std::logic_error("Attempt to iterate past end of Sequence");
@@ -169,10 +182,12 @@ const Sequence::const_iterator& Sequence::const_iterator::operator++()
assert(_event->buffer() && _event->buffer()[0] != '\0');
- /*cerr << "const_iterator::operator++: " << _event->to_string() << endl;*/
+ //debugout << "const_iterator::operator++: " << _event->to_string() << endl;
- if (! (_event->is_note() || _event->is_cc() || _event->is_pgm_change() || _event->is_pitch_bender() || _event->is_channel_aftertouch()) ) {
- cerr << "FAILED event buffer: " << hex << int(_event->buffer()[0]) << int(_event->buffer()[1]) << int(_event->buffer()[2]) << endl;
+ if (! (_event->is_note() || _event->is_cc() || _event->is_pgm_change()
+ || _event->is_pitch_bender() || _event->is_channel_aftertouch()) ) {
+ errorout << "Unknown event type: " << hex << int(_event->buffer()[0])
+ << int(_event->buffer()[1]) << int(_event->buffer()[2]) << endl;
}
assert((_event->is_note() || _event->is_cc() || _event->is_pgm_change() || _event->is_pitch_bender() || _event->is_channel_aftertouch()));
@@ -202,7 +217,7 @@ const Sequence::const_iterator& Sequence::const_iterator::operator++()
}
}
- enum Type {NIL, NOTE_ON, NOTE_OFF, AUTOMATION};
+ enum Type {NIL, NOTE_ON, NOTE_OFF, CONTROL};
Type type = NIL;
double t = 0;
@@ -222,26 +237,27 @@ const Sequence::const_iterator& Sequence::const_iterator::operator++()
}
// Use the next earliest controller iff it's earlier than the note event
- if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX /*&& _control_iter != old_control_iter */) {
+ if (_control_iter != _control_iters.end() && _control_iter->x != DBL_MAX
+ && _control_iter != old_control_iter) {
if (type == NIL || _control_iter->x < t) {
- type = AUTOMATION;
+ type = CONTROL;
}
}
if (type == NOTE_ON) {
- //cerr << "********** MIDI Iterator = note on" << endl;
+ debugout << "Iterator = note on" << endl;
*_event = (*_note_iter)->on_event();
_active_notes.push(*_note_iter);
++_note_iter;
} else if (type == NOTE_OFF) {
- //cerr << "********** MIDI Iterator = note off" << endl;
+ debugout << "Iterator = note off" << endl;
*_event = _active_notes.top()->off_event();
_active_notes.pop();
- } else if (type == AUTOMATION) {
- //cerr << "********** MIDI Iterator = Automation" << endl;
+ } else if (type == CONTROL) {
+ debugout << "Iterator = control" << endl;
_seq->control_to_midi_event(_event, *_control_iter);
} else {
- //cerr << "********** MIDI Iterator = End" << endl;
+ debugout << "Iterator = End" << endl;
_is_end = true;
}
@@ -250,7 +266,8 @@ const Sequence::const_iterator& Sequence::const_iterator::operator++()
return *this;
}
-bool Sequence::const_iterator::operator==(const const_iterator& other) const
+bool
+Sequence::const_iterator::operator==(const const_iterator& other) const
{
if (_is_end || other._is_end) {
return (_is_end == other._is_end);
@@ -259,7 +276,8 @@ bool Sequence::const_iterator::operator==(const const_iterator& other) const
}
}
-Sequence::const_iterator& Sequence::const_iterator::operator=(const const_iterator& other)
+Sequence::const_iterator&
+Sequence::const_iterator::operator=(const const_iterator& other)
{
if (_locked && _seq != other._seq) {
_seq->read_unlock();
@@ -292,6 +310,7 @@ Sequence::Sequence(size_t size)
, _next_read(UINT32_MAX)
, _percussive(false)
{
+ debugout << "Sequence (size " << size << ") constructed: " << this << endl;
assert(_end_iter._is_end);
assert( ! _end_iter._locked);
}
@@ -300,18 +319,21 @@ Sequence::Sequence(size_t size)
* adding \a offset to each event's timestamp.
* \return number of events written to \a dst
*/
-size_t Sequence::read(EventSink& dst, timestamp_t start, timestamp_t nframes, timedur_t offset) const
+size_t
+Sequence::read(EventSink& dst, timestamp_t start, timedur_t nframes, timestamp_t offset) const
{
- //cerr << this << " MM::read @ " << start << " frames: " << nframes << " -> " << stamp_offset << endl;
- //cerr << this << " MM # notes: " << n_notes() << endl;
+ debugout << this << " read ev @ " << start << " * " << nframes << " + " << offset << endl;
+ debugout << this << " # notes: " << n_notes() << endl;
+ debugout << this << " controls: " << &_controls << endl;
+ debugout << this << " # controls: " << _controls.size() << endl;
size_t read_events = 0;
if (start != _next_read) {
_read_iter = const_iterator(*this, (double)start);
- //cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
+ debugout << "Repositioning iterator from " << _next_read << " to " << start << endl;
} else {
- //cerr << "Using cached iterator at " << _next_read << endl;
+ debugout << "Using cached iterator at " << _next_read << endl;
}
_next_read = (nframes_t) floor (start + nframes);
@@ -323,11 +345,11 @@ size_t Sequence::read(EventSink& dst, timestamp_t start, timestamp_t nframes, ti
_read_iter->size(),
_read_iter->buffer());
- /*cerr << this << " Sequence::read event @ " << _read_iter->time()
- << " type: " << hex << int(_read_iter->type()) << dec
- << " note: " << int(_read_iter->note())
- << " velocity: " << int(_read_iter->velocity())
- << endl;*/
+ debugout << this << " read event @ " << _read_iter->time()
+ << " type: " << hex << int(_read_iter->type()) << dec
+ << " note: " << int(_read_iter->note())
+ << " velocity: " << int(_read_iter->velocity())
+ << endl;
++_read_iter;
++read_events;
@@ -406,10 +428,10 @@ Sequence::control_to_midi_event(boost::shared_ptr<Event>& ev, const ControlItera
return true;
}
-
/** Clear all events from the model.
*/
-void Sequence::clear()
+void
+Sequence::clear()
{
_lock.writer_lock();
_notes.clear();
@@ -420,7 +442,6 @@ void Sequence::clear()
_lock.writer_unlock();
}
-
/** Begin a write of events to the model.
*
* If \a mode is Sustained, complete notes with duration are constructed as note
@@ -428,9 +449,10 @@ void Sequence::clear()
* stored; note off events are discarded entirely and all contained notes will
* have duration 0.
*/
-void Sequence::start_write()
+void
+Sequence::start_write()
{
- //cerr << "MM " << this << " START WRITE, PERCUSSIVE = " << _percussive << endl;
+ debugout << this << " START WRITE, PERCUSSIVE = " << _percussive << endl;
write_lock();
_writing = true;
for (int i = 0; i < 16; ++i)
@@ -446,17 +468,18 @@ void Sequence::start_write()
* that were never resolved with a corresonding note off will be deleted.
* Otherwise they will remain as notes with duration 0.
*/
-void Sequence::end_write(bool delete_stuck)
+void
+Sequence::end_write(bool delete_stuck)
{
write_lock();
assert(_writing);
- //cerr << "MM " << this << " END WRITE: " << _notes.size() << " NOTES\n";
+ debugout << this << " END WRITE: " << _notes.size() << " NOTES\n";
if (!_percussive && delete_stuck) {
for (Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
if ((*n)->duration() == 0) {
- cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
+ errorout << "WARNING: Stuck note lost: " << (*n)->note() << endl;
n = _notes.erase(n);
// we have to break here because erase invalidates the iterator
break;
@@ -468,7 +491,7 @@ void Sequence::end_write(bool delete_stuck)
for (int i = 0; i < 16; ++i) {
if (!_write_notes[i].empty()) {
- cerr << "WARNING: Sequence::end_write: Channel " << i << " has "
+ errorout << "WARNING: Sequence::end_write: Channel " << i << " has "
<< _write_notes[i].size() << " stuck notes" << endl;
}
_write_notes[i].clear();
@@ -488,7 +511,8 @@ void Sequence::end_write(bool delete_stuck)
* the start of this model (t=0) and MUST be monotonically increasing
* and MUST be >= the latest event currently in the model.
*/
-void Sequence::append(const Event& ev)
+void
+Sequence::append(const Event& ev)
{
write_lock();
_edited = true;
@@ -503,7 +527,7 @@ void Sequence::append(const Event& ev)
append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
} else if (ev.is_cc()) {
append_control_unlocked(
- Evoral::MIDI::ContinuousController(midi_cc_type, ev.cc_number(), ev.channel()),
+ Evoral::MIDI::ContinuousController(midi_cc_type, ev.channel(), ev.cc_number()),
ev.time(), ev.cc_value());
} else if (ev.is_pgm_change()) {
append_control_unlocked(
@@ -525,12 +549,10 @@ void Sequence::append(const Event& ev)
write_unlock();
}
-void Sequence::append_note_on_unlocked(uint8_t chan, double time,
- uint8_t note_num, uint8_t velocity)
+void
+Sequence::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, uint8_t velocity)
{
- /*cerr << "Sequence " << this << " chan " << (int)chan <<
- " note " << (int)note_num << " on @ " << time << endl;*/
-
+ debugout << this << " c" << (int)chan << " note " << (int)note_num << " off @ " << time << endl;
assert(note_num <= 127);
assert(chan < 16);
assert(_writing);
@@ -539,26 +561,24 @@ void Sequence::append_note_on_unlocked(uint8_t chan, double time,
boost::shared_ptr<Note> new_note(new Note(chan, time, 0, note_num, velocity));
_notes.push_back(new_note);
if (!_percussive) {
- //cerr << "MM Sustained: Appending active note on " << (unsigned)(uint8_t)note_num << endl;
+ debugout << "Sustained: Appending active note on " << (unsigned)(uint8_t)note_num << endl;
_write_notes[chan].push_back(_notes.size() - 1);
- }/* else {
- cerr << "MM Percussive: NOT appending active note on" << endl;
- }*/
+ } else {
+ debugout << "Percussive: NOT appending active note on" << endl;
+ }
}
-void Sequence::append_note_off_unlocked(uint8_t chan, double time,
- uint8_t note_num)
+void
+Sequence::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
{
- /*cerr << "Sequence " << this << " chan " << (int)chan <<
- " note " << (int)note_num << " off @ " << time << endl;*/
-
+ debugout << this << " c" << (int)chan << " note " << (int)note_num << " off @ " << time << endl;
assert(note_num <= 127);
assert(chan < 16);
assert(_writing);
_edited = true;
if (_percussive) {
- cerr << "Sequence Ignoring note off (percussive mode)" << endl;
+ debugout << "Sequence Ignoring note off (percussive mode)" << endl;
return;
}
@@ -576,37 +596,43 @@ void Sequence::append_note_off_unlocked(uint8_t chan, double time,
assert(time >= note.time());
note.set_duration(time - note.time());
_write_notes[chan].erase(n);
- //cerr << "MM resolved note, duration: " << note.duration() << endl;
+ debugout << "resolved note, duration: " << note.duration() << endl;
resolved = true;
break;
}
}
if (!resolved) {
- cerr << "Sequence " << this << " spurious note off chan " << (int)chan
+ errorout << this << " spurious note off chan " << (int)chan
<< ", note " << (int)note_num << " @ " << time << endl;
}
}
-void Sequence::append_control_unlocked(const Parameter& param, double time, double value)
+void
+Sequence::append_control_unlocked(const Parameter& param, double time, double value)
{
+ debugout << this << " " << param.symbol() << " @ " << time << " = " << value
+ << " controls: " << &_controls
+ << " # controls: " << _controls.size() << endl;
control(param, true)->list()->rt_add(time, value);
}
-void Sequence::add_note_unlocked(const boost::shared_ptr<Note> note)
+void
+Sequence::add_note_unlocked(const boost::shared_ptr<Note> note)
{
- //cerr << "Sequence " << this << " add note " << (int)note.note() << " @ " << note.time() << endl;
+ debugout << this << " add note " << (int)note->note() << " @ " << note->time() << endl;
_edited = true;
Notes::iterator i = upper_bound(_notes.begin(), _notes.end(), note,
note_time_comparator);
_notes.insert(i, note);
}
-void Sequence::remove_note_unlocked(const boost::shared_ptr<const Note> note)
+void
+Sequence::remove_note_unlocked(const boost::shared_ptr<const Note> note)
{
_edited = true;
- //cerr << "Sequence " << this << " remove note " << (int)note.note() << " @ " << note.time() << endl;
+ debugout << this << " remove note " << (int)note->note() << " @ " << note->time() << endl;
for (Notes::iterator n = _notes.begin(); n != _notes.end(); ++n) {
Note& _n = *(*n);
const Note& _note = *note;
@@ -628,7 +654,8 @@ void Sequence::remove_note_unlocked(const boost::shared_ptr<const Note> note)
/** Slow! for debugging only. */
#ifndef NDEBUG
-bool Sequence::is_sorted() const {
+bool
+Sequence::is_sorted() const {
bool t = 0;
for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n)
if ((*n)->time() < t)