Fix crash when changing automation mode for MIDI track control automation.
authorDavid Robillard <d@drobilla.net>
Sun, 31 Aug 2014 22:52:37 +0000 (18:52 -0400)
committerDavid Robillard <d@drobilla.net>
Sun, 31 Aug 2014 22:57:22 +0000 (18:57 -0400)
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
libs/ardour/automatable.cc
libs/ardour/automation_control.cc
libs/ardour/midi_track.cc
libs/evoral/src/ControlSet.cpp

index 1acec0346eb4ecf7cc75322da26bcf9df9be41fd..cea3af5aeda5f6254aefe9af5774c99d0b63430d 100644 (file)
@@ -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);
 
index 7669f22df16c68d8782d557c0553d40c373c91a0..8629722889de2fe5d86a65140893146237addcbe 100644 (file)
@@ -137,16 +137,20 @@ Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
        Evoral::Parameter param = ac->parameter();
 
        boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (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<MidiTrack*>(this);
                if (mt) {
                        control = new MidiTrack::MidiControl(mt, param);
+                       list.reset();  // No list, this is region "automation"
                } else {
                        warning << "MidiCCAutomation for non-MidiTrack" << endl;
                }
index 355b0176ced0fe09ad8f6933dad613c4901a8a94..2bb694c7e5d2ca6031dd9b0524521c71b3eb580e 100644 (file)
@@ -85,7 +85,7 @@ AutomationControl::set_list (boost::shared_ptr<Evoral::ControlList> list)
 void
 AutomationControl::set_automation_state (AutoState as)
 {
-       if (as != alist()->automation_state()) {
+       if (_list && as != alist()->automation_state()) {
 
                alist()->set_automation_state (as);
 
index 638ed057063a56b08b0e2f034fa4d6cc1d336260..3866eb4d80844f4790bbb418725911a69736d4a3 100644 (file)
@@ -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)
 {
index 393b819146932f6187bd5e28a85825da3fef6b79..f24c410d730038dad1f9fe4b3aa56529ca6d9a8f 100644 (file)
@@ -45,9 +45,12 @@ ControlSet::add_control(boost::shared_ptr<Control> 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<const ControlList> 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