From f1ce235b6bc10a336822a052cee517fa923def48 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 28 Mar 2013 17:10:57 -0400 Subject: some deep tweaking to get MIDI channel control into nearly done shape for 3.1 --- gtk2_ardour/midi_channel_selector.cc | 451 +++++++++++++++++++++++++---------- 1 file changed, 328 insertions(+), 123 deletions(-) (limited to 'gtk2_ardour/midi_channel_selector.cc') diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc index aea9d31f03..2f5ca729a6 100644 --- a/gtk2_ardour/midi_channel_selector.cc +++ b/gtk2_ardour/midi_channel_selector.cc @@ -1,6 +1,6 @@ /* - Copyright (C) 2008 Paul Davis - Author: Hans Baier + Copyright (C) 2008-2013 Paul Davis + Original Author: Hans Baier This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ #include "gtkmm2ext/gtk_ui.h" #include "gtkmm2ext/gui_thread.h" +#include "gtkmm2ext/utils.h" #include "ardour/midi_track.h" @@ -326,16 +327,25 @@ MidiMultipleChannelSelector::invert_selection(void) /*-----------------------------------------*/ MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr mt) - : ArdourWindow (string_compose (_("MIDI Channel Control for %1"), mt->name())) + : ArdourWindow (_("MIDI Channel Control")) , track (mt) + , playback_all_button (playback_button_group, _("Playback all channels")) + , playback_filter_button (playback_button_group, _("Play only selected channels")) + , playback_force_button (playback_button_group, _("Use a single fixed channel for all playback")) + , capture_all_button (capture_button_group, _("Record all channels")) + , capture_filter_button (capture_button_group, _("Record only selected channels")) + , capture_force_button (capture_button_group, _("Force all channels to 1 channel")) + , last_drawn_capture_mode (AllChannels) + , last_drawn_playback_mode (AllChannels) { build (); - playback_mask_changed (); playback_mode_changed (); - capture_mask_changed (); capture_mode_changed (); + playback_mask_changed (); + capture_mask_changed (); + track->PlaybackChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context()); track->PlaybackChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context()); track->CaptureChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context()); @@ -350,122 +360,93 @@ void MidiChannelSelectorWindow::build () { VBox* vpacker; - HBox* capture_mask; - HBox* capture_mask_controls; - HBox* playback_mask; - HBox* playback_mask_controls; + HBox* capture_controls; + HBox* playback_controls; Button* b; - ToggleButton* tb; Label* l; vpacker = manage (new VBox); vpacker->set_spacing (6); vpacker->set_border_width (12); - l = manage (new Label (string_compose ("%1", _("Capture")))); + l = manage (new Label (string_compose (("%1: %2"), _("MIDI Channel Control"), track->name()))); l->set_use_markup (true); - vpacker->pack_start (*l); - - { - RadioButtonGroup group; + l->set_alignment (0.5, 0.0); - capture_all_button = manage (new RadioButton (group, "Record all channels")); - vpacker->pack_start (*capture_all_button); - capture_all_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels)); + vpacker->pack_start (*l, true, true); - capture_filter_button = manage (new RadioButton (group, "Record only selected channels")); - vpacker->pack_start (*capture_filter_button); - capture_filter_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels)); - - capture_force_button = manage (new RadioButton (group, "Force all channels to a single fixed channel")); - vpacker->pack_start (*capture_force_button); - capture_force_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), ForceChannel)); - } - - capture_mask = manage (new HBox); + l = manage (new Label (string_compose ("%1", _("Inbound")))); + l->set_use_markup (true); + vpacker->pack_start (*l); - for (uint32_t n = 0; n < 16; ++n) { - char buf[3]; - snprintf (buf, sizeof (buf), "%d", n+1); - tb = manage (new ToggleButton (buf)); - Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle recording of channel %1"), n+1)); - capture_buttons.push_back (tb); - tb->set_name (X_("MidiChannelSelectorButton")); - capture_mask->pack_start (*tb); - tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_channel_clicked), n)); - } - vpacker->pack_start (*capture_mask); + vpacker->pack_start (capture_all_button); + capture_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels)); + + vpacker->pack_start (capture_filter_button); + capture_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels)); + + vpacker->pack_start (capture_force_button); + capture_force_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), ForceChannel)); - capture_mask_controls = manage (new HBox); - capture_mask_controls->set_spacing (6); + vpacker->pack_start (capture_mask_box); + + capture_controls = manage (new HBox); + capture_controls->set_spacing (6); b = manage (new Button (_("All"))); Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable recording all channels")); - capture_mask_controls->pack_start (*b); + capture_controls->pack_start (*b); + capture_mask_controls.push_back (b); b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_capture_mask)); b = manage (new Button (_("None"))); Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable recording all channels")); - capture_mask_controls->pack_start (*b); + capture_controls->pack_start (*b); + capture_mask_controls.push_back (b); b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_capture_mask)); b = manage (new Button (_("Invert"))); Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert currently selected recording channels")); - capture_mask_controls->pack_start (*b); + capture_controls->pack_start (*b); + capture_mask_controls.push_back (b); b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_capture_mask)); - vpacker->pack_start (*capture_mask_controls); - - playback_mask = manage (new HBox); + vpacker->pack_start (*capture_controls); l = manage (new Label (string_compose ("%1", _("Playback")))); l->set_use_markup (true); vpacker->pack_start (*l); - { - RadioButtonGroup group; - - playback_all_button = manage (new RadioButton (group, "Playback all channels")); - vpacker->pack_start (*playback_all_button); - playback_all_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), AllChannels)); - - playback_filter_button = manage (new RadioButton (group, "Play only selected channels")); - vpacker->pack_start (*playback_filter_button); - playback_filter_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels)); + vpacker->pack_start (playback_all_button); + playback_all_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), AllChannels)); + + vpacker->pack_start (playback_filter_button); + playback_filter_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels)); + + vpacker->pack_start (playback_force_button); + playback_force_button.signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), ForceChannel)); - playback_force_button = manage (new RadioButton (group, "Use a single fixed channel for all playback")); - vpacker->pack_start (*playback_force_button); - playback_force_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), ForceChannel)); - } + vpacker->pack_start (playback_mask_box); - for (uint32_t n = 0; n < 16; ++n) { - char buf[3]; - snprintf (buf, sizeof (buf), "%d", n+1); - tb = manage (new ToggleButton (buf)); - tb->set_name (X_("MidiChannelSelectorButton")); - playback_buttons.push_back (tb); - playback_mask->pack_start (*tb); - tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_channel_clicked), n)); - } - - vpacker->pack_start (*playback_mask); - - playback_mask_controls = manage (new HBox); - playback_mask_controls->set_spacing (6); + playback_controls = manage (new HBox); + playback_controls->set_spacing (6); b = manage (new Button (_("All"))); Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable playback of all channels")); - playback_mask_controls->pack_start (*b); + playback_controls->pack_start (*b); + playback_mask_controls.push_back (b); b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_playback_mask)); b = manage (new Button (_("None"))); Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable playback of all channels")); - playback_mask_controls->pack_start (*b); + playback_controls->pack_start (*b); + playback_mask_controls.push_back (b); b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_playback_mask)); b = manage (new Button (_("Invert"))); Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert current selected playback channels")); - playback_mask_controls->pack_start (*b); + playback_controls->pack_start (*b); + playback_mask_controls.push_back (b); b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_playback_mask)); - vpacker->pack_start (*playback_mask_controls); + vpacker->pack_start (*playback_controls); add (*vpacker); } @@ -473,52 +454,94 @@ MidiChannelSelectorWindow::build () void MidiChannelSelectorWindow::fill_playback_mask () { - track->set_playback_channel_mask (0xffff); + if (track->get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (0xffff); + } } void MidiChannelSelectorWindow::zero_playback_mask () { - track->set_playback_channel_mask (0); + if (track->get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (0); + } } void MidiChannelSelectorWindow::invert_playback_mask () { - track->set_playback_channel_mask (~track->get_playback_channel_mask()); + if (track->get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (~track->get_playback_channel_mask()); + } } void MidiChannelSelectorWindow::fill_capture_mask () { - track->set_capture_channel_mask (0xffff); + if (track->get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (0xffff); + } } void MidiChannelSelectorWindow::zero_capture_mask () { - track->set_capture_channel_mask (0); + if (track->get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (0); + } } void MidiChannelSelectorWindow::invert_capture_mask () { - track->set_capture_channel_mask (~track->get_capture_channel_mask()); + if (track->get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (~track->get_capture_channel_mask()); + } } void MidiChannelSelectorWindow::set_playback_selected_channels (uint16_t mask) { - for (uint16_t i = 0; i < 16; i++) { - playback_buttons[i]->set_active ((1<get_playback_channel_mode()) { + case AllChannels: + /* they are insensitive, so we don't care */ + break; + + case FilterChannels: + for (uint16_t i = 0; i < 16; i++) { + playback_buttons[i]->set_active ((1<set_active (i == (ffs (mask) - 1)); + } + break; } } void MidiChannelSelectorWindow::set_capture_selected_channels (uint16_t mask) { - for (uint16_t i = 0; i < 16; i++) { - capture_buttons[i]->set_active ((1<get_capture_channel_mode()) { + case AllChannels: + /* they are insensitive, so we don't care */ + break; + + case FilterChannels: + for (uint16_t i = 0; i < 16; i++) { + capture_buttons[i]->set_active ((1<set_active (i == (ffs (mask) - 1)); + } + break; } } @@ -537,42 +560,217 @@ MidiChannelSelectorWindow::capture_mask_changed () void MidiChannelSelectorWindow::playback_mode_changed () { - switch (track->get_playback_channel_mode()) { + uint32_t first_channel = 0; + ChannelMode mode = track->get_playback_channel_mode(); + + switch (mode) { case AllChannels: - playback_all_button->set_active (); + if (last_drawn_playback_mode == ForceChannel) { + /* force mode used radio buttons. not what we want, + * though one could argue that we want no buttons + * at since they are insensitive + */ + playback_buttons.clear (); + } + for (vector::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) { + (*i)->set_sensitive (false); + } + playback_all_button.set_active (); break; + case FilterChannels: - playback_filter_button->set_active (); + if (last_drawn_playback_mode == ForceChannel) { + playback_buttons.clear (); + } else if (last_drawn_playback_mode == AllChannels) { + for (vector::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) { + (*i)->set_sensitive (true); + } + } + for (vector::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) { + (*i)->set_sensitive (true); + } + playback_filter_button.set_active (); break; + case ForceChannel: - playback_force_button->set_active (); + if (last_drawn_playback_mode == AllChannels || last_drawn_playback_mode == FilterChannels) { + playback_buttons.clear (); + first_channel = ffs (track->get_playback_channel_mask()) - 1; + } + for (vector::iterator i = playback_mask_controls.begin(); i != playback_mask_controls.end(); ++i) { + (*i)->set_sensitive (false); + } + playback_force_button.set_active (); break; } + + if (playback_buttons.empty()) { + + Gtkmm2ext::container_clear (playback_mask_box); + + ToggleButton* tb; + RadioButtonGroup group; + + for (uint32_t n = 0; n < 16; ++n) { + char buf[3]; + snprintf (buf, sizeof (buf), "%d", n+1); + + switch (mode) { + case AllChannels: + case FilterChannels: + tb = manage (new ToggleButton (buf)); + Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle playback of channel %1"), n+1)); + break; + case ForceChannel: + tb = manage (new RadioButton (group, buf)); + tb->property_draw_indicator() = false; + if (n == first_channel) { + tb->set_active (true); + } + Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to force all MIDI channel messages to channel %1"), n+1)); + break; + } + playback_buttons.push_back (tb); + tb->set_name (X_("MidiChannelSelectorButton")); + playback_mask_box.pack_start (*tb); + tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_channel_clicked), n)); + tb->show (); + + if (mode == AllChannels) { + tb->set_sensitive (false); + } + } + + if (mode != ForceChannel) { + set_playback_selected_channels (track->get_playback_channel_mask()); + } + } + + if (mode == AllChannels) { + for (vector::iterator i = playback_buttons.begin(); i != playback_buttons.end(); ++i) { + (*i)->set_sensitive (false); + } + } + + last_drawn_playback_mode = mode; } void MidiChannelSelectorWindow::capture_mode_changed () { - switch (track->get_capture_channel_mode()) { + uint32_t first_channel = 0; + ChannelMode mode = track->get_capture_channel_mode(); + + switch (mode) { case AllChannels: - capture_all_button->set_active (); + if (last_drawn_capture_mode == ForceChannel) { + /* force mode used radio buttons. not what we want, + * though one could argue that we want no buttons + * at since they are insensitive + */ + capture_buttons.clear (); + } + for (vector::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) { + (*i)->set_sensitive (false); + } + capture_all_button.set_active (); break; + case FilterChannels: - capture_filter_button->set_active (); + if (last_drawn_capture_mode == ForceChannel) { + capture_buttons.clear (); + } else if (last_drawn_capture_mode == AllChannels) { + for (vector::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) { + (*i)->set_sensitive (true); + } + } + for (vector::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) { + (*i)->set_sensitive (true); + } + capture_filter_button.set_active (); break; + case ForceChannel: - capture_force_button->set_active (); + if (last_drawn_capture_mode == AllChannels || last_drawn_capture_mode == FilterChannels) { + capture_buttons.clear (); + first_channel = ffs (track->get_capture_channel_mask()) - 1; + } + for (vector::iterator i = capture_mask_controls.begin(); i != capture_mask_controls.end(); ++i) { + (*i)->set_sensitive (false); + } + capture_force_button.set_active (); break; } + + if (capture_buttons.empty()) { + + Gtkmm2ext::container_clear (capture_mask_box); + + ToggleButton* tb; + RadioButtonGroup group; + + for (uint32_t n = 0; n < 16; ++n) { + char buf[3]; + snprintf (buf, sizeof (buf), "%d", n+1); + + switch (mode) { + case AllChannels: + case FilterChannels: + tb = manage (new ToggleButton (buf)); + Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle recording of channel %1"), n+1)); + break; + case ForceChannel: + tb = manage (new RadioButton (group, buf)); + tb->property_draw_indicator() = false; + if (n == first_channel) { + tb->set_active (true); + } + Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to force all recorded channels to %1"), n+1)); + break; + } + capture_buttons.push_back (tb); + tb->set_name (X_("MidiChannelSelectorButton")); + capture_mask_box.pack_start (*tb); + tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_channel_clicked), n)); + tb->show (); + + if (mode == AllChannels) { + tb->set_sensitive (false); + } + } + + if (mode != ForceChannel) { + set_capture_selected_channels (track->get_capture_channel_mask()); + } + } + + if (mode == AllChannels) { + for (vector::iterator i = capture_buttons.begin(); i != capture_buttons.end(); ++i) { + (*i)->set_sensitive (false); + } + } + + last_drawn_capture_mode = mode; } void MidiChannelSelectorWindow::playback_channel_clicked (uint16_t n) { if (playback_buttons[n]->get_active()) { - track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<get_playback_channel_mode()) { + case AllChannels: + break; + case FilterChannels: + track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<set_playback_channel_mask (1<set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<get_playback_channel_mode() == FilterChannels) { + track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<get_active()) { - track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<get_capture_channel_mode()) { + case AllChannels: + break; + case FilterChannels: + track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<set_capture_channel_mask (1<set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<get_capture_channel_mode() == FilterChannels) { + track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<get_active()) { - return; + if (capture_all_button.get_active()) { + track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask()); } - track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask()); break; case FilterChannels: - if (!capture_filter_button->get_active()) { - return; + if (capture_filter_button.get_active()) { + track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask()); } - track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask()); break; case ForceChannel: - if (!capture_force_button->get_active()) { - return; + if (capture_force_button.get_active()) { + track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask()); } - track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask()); break; } } @@ -625,27 +832,25 @@ MidiChannelSelectorWindow::playback_mode_toggled (ChannelMode mode) is for the button/mode that has been turned off, and the second is for the button/mode that has been turned on. - so we have to check the button state to know what to do. + so we take action only if the button is active (i.e it is the one + just clicked on) */ - + switch (mode) { case AllChannels: - if (!playback_all_button->get_active()) { - return; + if (playback_all_button.get_active()) { + track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask()); } - track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask()); break; case FilterChannels: - if (!playback_filter_button->get_active()) { - return; + if (playback_filter_button.get_active()) { + track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask()); } - track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask()); break; case ForceChannel: - if (!playback_force_button->get_active()) { - return; + if (playback_force_button.get_active()) { + track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask()); } - track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask()); break; } } -- cgit v1.2.3