From 34c1465cf9645fce4e05299f6e5a2e7af19a0d3e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 31 Aug 2014 18:52:37 -0400 Subject: [PATCH] Fix crash when changing automation mode for MIDI track control automation. Also some work towards tolerating automation controls with no automation list, towards actually doing something for these cases, though not required just to fix this crash (MidiTrack::set_parameter_automation_state() avoids those paths). --- libs/ardour/ardour/midi_track.h | 2 ++ libs/ardour/automatable.cc | 15 ++++++++++----- libs/ardour/automation_control.cc | 2 +- libs/ardour/midi_track.cc | 18 ++++++++++++++++++ libs/evoral/src/ControlSet.cpp | 19 ++++++++++++++----- 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 1acec0346e..cea3af5aed 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -93,6 +93,8 @@ public: MidiTrack* _route; }; + virtual void set_parameter_automation_state (Evoral::Parameter param, AutoState); + NoteMode note_mode() const { return _note_mode; } void set_note_mode (NoteMode m); diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 7669f22df1..8629722889 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -137,16 +137,20 @@ Automatable::add_control(boost::shared_ptr ac) Evoral::Parameter param = ac->parameter(); boost::shared_ptr al = boost::dynamic_pointer_cast (ac->list ()); - assert (al); - al->automation_state_changed.connect_same_thread ( - _list_connections, boost::bind (&Automatable::automation_list_automation_state_changed, this, ac->parameter(), _1) - ); + if (al) { + al->automation_state_changed.connect_same_thread ( + _list_connections, + boost::bind (&Automatable::automation_list_automation_state_changed, + this, ac->parameter(), _1)); + } ControlSet::add_control (ac); _can_automate_list.insert (param); - automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up + if (al) { + automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up + } } string @@ -394,6 +398,7 @@ Automatable::control_factory(const Evoral::Parameter& param) MidiTrack* mt = dynamic_cast(this); if (mt) { control = new MidiTrack::MidiControl(mt, param); + list.reset(); // No list, this is region "automation" } else { warning << "MidiCCAutomation for non-MidiTrack" << endl; } diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc index 355b0176ce..2bb694c7e5 100644 --- a/libs/ardour/automation_control.cc +++ b/libs/ardour/automation_control.cc @@ -85,7 +85,7 @@ AutomationControl::set_list (boost::shared_ptr list) void AutomationControl::set_automation_state (AutoState as) { - if (as != alist()->automation_state()) { + if (_list && as != alist()->automation_state()) { alist()->set_automation_state (as); diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 638ed05706..3866eb4d80 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -622,6 +622,24 @@ MidiTrack::write_immediate_event(size_t size, const uint8_t* buf) return (_immediate_events.write(0, type, size, buf) == size); } +void +MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState state) +{ + switch (param.type()) { + case MidiCCAutomation: + case MidiPgmChangeAutomation: + case MidiPitchBenderAutomation: + case MidiChannelPressureAutomation: + case MidiSystemExclusiveAutomation: + /* The track control for MIDI parameters is for immediate events to act + as a control surface, write/touch for them is not currently + supported. */ + return; + default: + Automatable::set_parameter_automation_state(param, state); + } +} + void MidiTrack::MidiControl::set_value(double val) { diff --git a/libs/evoral/src/ControlSet.cpp b/libs/evoral/src/ControlSet.cpp index 393b819146..f24c410d73 100644 --- a/libs/evoral/src/ControlSet.cpp +++ b/libs/evoral/src/ControlSet.cpp @@ -45,9 +45,12 @@ ControlSet::add_control(boost::shared_ptr ac) ac->ListMarkedDirty.connect_same_thread (_control_connections, boost::bind (&ControlSet::control_list_marked_dirty, this)); - ac->list()->InterpolationChanged.connect_same_thread ( - _list_connections, boost::bind (&ControlSet::control_list_interpolation_changed, this, ac->parameter(), _1) - ); + if (ac->list()) { + ac->list()->InterpolationChanged.connect_same_thread ( + _list_connections, + boost::bind (&ControlSet::control_list_interpolation_changed, + this, ac->parameter(), _1)); + } } void @@ -95,6 +98,9 @@ ControlSet::find_next_event (double now, double end, ControlEvent& next_event) c ControlList::const_iterator i; boost::shared_ptr alist (li->second->list()); ControlEvent cp (now, 0.0f); + if (!alist) { + continue; + } for (i = lower_bound (alist->begin(), alist->end(), &cp, ControlList::time_comparator); i != alist->end() && (*i)->when < end; ++i) { @@ -121,8 +127,11 @@ ControlSet::clear_controls () _control_connections.drop_connections (); _list_connections.drop_connections (); - for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) - li->second->list()->clear(); + for (Controls::iterator li = _controls.begin(); li != _controls.end(); ++li) { + if (li->second->list()) { + li->second->list()->clear(); + } + } } } // namespace Evoral