diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index 2f5c80497c..9f3da122c5 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -304,13 +304,15 @@ MidiTimeAxisView::build_automation_action_menu () automation_items.push_back (SeparatorElem()); automation_items.push_back (MenuElem (_("Controller..."), mem_fun(*this, &MidiTimeAxisView::add_cc_track))); + automation_items.push_back (MenuElem (_("Program Change"), + sigc::bind(mem_fun(*this, &MidiTimeAxisView::add_parameter_track), + Evoral::Parameter(MidiPgmChangeAutomation)))); automation_items.push_back (MenuElem (_("Bender"), sigc::bind(mem_fun(*this, &MidiTimeAxisView::add_parameter_track), Evoral::Parameter(MidiPitchBenderAutomation)))); automation_items.push_back (MenuElem (_("Pressure"), sigc::bind(mem_fun(*this, &MidiTimeAxisView::add_parameter_track), Evoral::Parameter(MidiChannelPressureAutomation)))); - } Gtk::Menu* @@ -467,49 +469,57 @@ MidiTimeAxisView::add_cc_track() void MidiTimeAxisView::add_parameter_track(const Evoral::Parameter& param) { - create_automation_child(param, true); + if ( param.type() != MidiCCAutomation && + param.type() != MidiPgmChangeAutomation && + param.type() != MidiPitchBenderAutomation && + param.type() != MidiChannelPressureAutomation + ) { + error << "MidiTimeAxisView: unknown automation child " + << ARDOUR::EventTypeMap::instance().to_symbol(param) << endmsg; + return; + } + + // create the parameter lane for each selected channel + uint16_t selected_channels = _channel_selector.get_selected_channels(); + + for (uint8_t i = 0; i < 16; i++) { + if (selected_channels & (0x0001 << i)) { + Evoral::Parameter param_with_channel(param.type(), i, param.id()); + create_automation_child(param_with_channel, true); + } + } } void MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show) { - if ( param.type() == MidiCCAutomation || - param.type() == MidiPgmChangeAutomation || - param.type() == MidiPitchBenderAutomation || - param.type() == MidiChannelPressureAutomation - ) { - - /* These controllers are region "automation", so we do not create - * an AutomationList/Line for the track */ + /* 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; + AutomationTracks::iterator existing = _automation_tracks.find(param); + if (existing != _automation_tracks.end()) + return; - boost::shared_ptr c - = boost::dynamic_pointer_cast(_route->data().control(param)); + boost::shared_ptr c + = boost::dynamic_pointer_cast(_route->data().control(param)); - if (!c) { - c = boost::dynamic_pointer_cast(_route->control_factory(param)); - _route->add_control(c); - } - - boost::shared_ptr track(new AutomationTimeAxisView (_session, - _route, boost::shared_ptr(), c, - _editor, - *this, - true, - parent_canvas, - _route->describe_parameter(param))); - - add_automation_child(param, track, show); - - } else { - error << "MidiTimeAxisView: unknown automation child " - << ARDOUR::EventTypeMap::instance().to_symbol(param) << endmsg; + if (!c) { + c = boost::dynamic_pointer_cast(_route->control_factory(param)); + _route->add_control(c); } + + boost::shared_ptr track(new AutomationTimeAxisView (_session, + _route, boost::shared_ptr(), c, + _editor, + *this, + true, + parent_canvas, + _route->describe_parameter(param))); + + add_automation_child(param, track, show); } + void MidiTimeAxisView::route_active_changed () { diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 5035814fa2..e544122ccd 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1665,7 +1665,8 @@ RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param) if (!ran) { return; } - + + // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here.... _show_automation.erase(param); ran->track->get_state_node()->add_property (X_("shown"), X_("no")); diff --git a/libs/evoral/evoral/Parameter.hpp b/libs/evoral/evoral/Parameter.hpp index ecc0129ccb..0f6d5afc4b 100644 --- a/libs/evoral/evoral/Parameter.hpp +++ b/libs/evoral/evoral/Parameter.hpp @@ -47,8 +47,8 @@ public: virtual ~Parameter() {} inline uint32_t type() const { return _type; } - inline uint32_t id() const { return _id; } inline uint8_t channel() const { return _channel; } + inline uint32_t id() const { return _id; } /** Equivalence operator * It is obvious from the definition that this operator @@ -56,7 +56,7 @@ public: * (see: http://www.sgi.com/tech/stl/StrictWeakOrdering.html) */ inline bool operator==(const Parameter& id) const { - return (_type == id._type && _id == id._id && _channel == id._channel); + return (_type == id._type && _channel == id._channel && _id == id._id ); } /** Strict weak ordering @@ -68,9 +68,11 @@ public: *
  • Irreflexivity: f(x, x) is false because of the irreflexivity of \c < in each branch.
  • *
  • Antisymmetry: given x != y, f(x, y) implies !f(y, x) because of the same * property of \c < in each branch and the symmetry of operator==.
  • - *
  • Transitivity: let f(x, y) and f(y, z) be true. - * We prove by contradiction, assuming the contrary (f(x, z) is false). - * That would imply exactly one of the following: + *
  • Transitivity: let f(x, y) and f(y, z) => f(x, z) be true. + * We prove by contradiction, assuming the contrary: + * f(x, y) and f(x, z) hold => !f(x, z) + * + * That implies one of the following: *
      *
    1. x == z which contradicts the assumption f(x, y) and f(y, x) * because of antisymmetry. @@ -87,12 +89,12 @@ public: *
    2. *
    */ - inline bool operator<(const Parameter& id) const { - if (_type < id._type) { + inline bool operator<(const Parameter& other) const { + if (_type < other._type) { return true; - } else if (_type == id._type && _id < id._id) { + } else if (_type == other._type && _channel < other._channel) { return true; - } else if (_id == id._id && _channel < id._channel) { + } else if (_type == other._type && _channel == other._channel && _id < other._id ) { return true; }