+ button->set_active(true);
+ _last_active_button = button;
+}
+
+void
+SingleMidiChannelSelector::button_toggled(ToggleButton* button, uint8_t channel)
+{
+ ++_recursion_counter;
+ if (_recursion_counter == 1) {
+ // if the current button is active it must
+ // be different from the first one
+ if (button->get_active()) {
+ if (_last_active_button) {
+ _last_active_button->set_active(false);
+ _active_channel = channel;
+ _last_active_button = button;
+ channel_selected.emit(channel);
+ }
+ } else {
+ // if not, the user pressed the already active button
+ button->set_active(true);
+ _active_channel = channel;
+ }
+ }
+ --_recursion_counter;
+}
+
+MidiMultipleChannelSelector::MidiMultipleChannelSelector(ChannelMode mode, uint16_t mask)
+ : MidiChannelSelector(4, 6, 0, 0)
+ , _channel_mode(mode)
+{
+ _select_all.add(*manage(new Label(_("All"))));
+ _select_all.signal_clicked().connect(
+ sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), true));
+
+ _select_none.add(*manage(new Label(_("None"))));
+ _select_none.signal_clicked().connect(
+ sigc::bind(sigc::mem_fun(this, &MidiMultipleChannelSelector::select_all), false));
+
+ _invert_selection.add(*manage(new Label(_("Invert"))));
+ _invert_selection.signal_clicked().connect(
+ sigc::mem_fun(this, &MidiMultipleChannelSelector::invert_selection));
+
+ _force_channel.add(*manage(new Label(_("Force"))));
+ _force_channel.signal_toggled().connect(
+ sigc::mem_fun(this, &MidiMultipleChannelSelector::force_channels_button_toggled));
+
+ set_homogeneous(false);
+ attach(*manage(new VSeparator()), 4, 5, 0, 4, SHRINK, FILL, 0, 0);
+ //set_row_spacing(4, -5);
+ attach(_select_all, 5, 6, 0, 1);
+ attach(_select_none, 5, 6, 1, 2);
+ attach(_invert_selection, 5, 6, 2, 3);
+ attach(_force_channel, 5, 6, 3, 4);
+
+ set_selected_channels(mask);
+}
+
+MidiMultipleChannelSelector::~MidiMultipleChannelSelector()
+{
+ mode_changed.clear();
+}
+
+void
+MidiMultipleChannelSelector::set_channel_mode(ChannelMode mode, uint16_t mask)
+{
+ switch (mode) {
+ case AllChannels:
+ _force_channel.set_active(false);
+ set_selected_channels(0xFFFF);
+ break;
+ case FilterChannels:
+ _force_channel.set_active(false);
+ set_selected_channels(mask);
+ break;
+ case ForceChannel:
+ _force_channel.set_active(true);
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ button->set_active(i == mask);
+ }
+ }
+}
+
+uint16_t
+MidiMultipleChannelSelector::get_selected_channels() const
+{
+ uint16_t selected_channels = 0;
+ for (uint16_t i = 0; i < 16; i++) {
+ const ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (button->get_active()) {
+ selected_channels |= (1L << i);
+ }
+ }
+
+ return selected_channels;
+}
+
+void
+MidiMultipleChannelSelector::set_selected_channels(uint16_t selected_channels)
+{
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (selected_channels & (1L << i)) {
+ button->set_active(true);
+ } else {
+ button->set_active(false);
+ }
+ }
+}
+
+void
+MidiMultipleChannelSelector::button_toggled(ToggleButton */*button*/, uint8_t channel)
+{
+ ++_recursion_counter;
+ if (_recursion_counter == 1) {
+ if (_channel_mode == ForceChannel) {
+ mode_changed.emit(_channel_mode, channel);
+ set_selected_channels(1 << channel);
+ } else {
+ mode_changed.emit(_channel_mode, get_selected_channels());
+ }
+ }
+ --_recursion_counter;
+}
+
+void
+MidiMultipleChannelSelector::force_channels_button_toggled()
+{
+ if (_force_channel.get_active()) {
+ _channel_mode = ForceChannel;
+ bool found_first_active = false;
+ // leave only the first button enabled
+ uint16_t active_channel = 0;
+ for (int i = 0; i <= 15; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (button->get_active()) {
+ if (found_first_active) {
+ ++_recursion_counter;
+ button->set_active(false);
+ --_recursion_counter;
+ } else {
+ found_first_active = true;
+ active_channel = i;
+ }
+ }
+ }
+
+ if (!found_first_active) {
+ _buttons[0][0].set_active(true);
+ }
+
+ _select_all.set_sensitive(false);
+ _select_none.set_sensitive(false);
+ _invert_selection.set_sensitive(false);
+ mode_changed.emit(_channel_mode, active_channel);
+ } else {
+ _channel_mode = FilterChannels;
+ _select_all.set_sensitive(true);
+ _select_none.set_sensitive(true);
+ _invert_selection.set_sensitive(true);
+ mode_changed.emit(FilterChannels, get_selected_channels());
+ }
+}
+
+void
+MidiMultipleChannelSelector::select_all(bool on)
+{
+ if (_channel_mode == ForceChannel)
+ return;
+
+ ++_recursion_counter;
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ button->set_active(on);
+ }
+ --_recursion_counter;
+ mode_changed.emit(_channel_mode, get_selected_channels());
+}
+
+void
+MidiMultipleChannelSelector::invert_selection(void)
+{
+ if (_channel_mode == ForceChannel)
+ return;
+
+ ++_recursion_counter;
+ for (uint16_t i = 0; i < 16; i++) {
+ ToggleButton* button = &_buttons[i / 4][i % 4];
+ if (button->get_active()) {
+ button->set_active(false);
+ } else {
+ button->set_active(true);
+ }
+ }
+ --_recursion_counter;
+ mode_changed.emit(_channel_mode, get_selected_channels());
+}
+
+/*-----------------------------------------*/
+
+MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrack> mt)
+ : 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_mode_changed ();
+ capture_mode_changed ();
+
+ playback_mask_changed ();
+ capture_mask_changed ();
+
+ track->playback_filter().ChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
+ track->playback_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
+ track->capture_filter().ChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
+ track->capture_filter().ChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
+}
+
+MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
+{
+}
+
+void
+MidiChannelSelectorWindow::build ()
+{
+ VBox* vpacker;
+ HBox* capture_controls;
+ HBox* playback_controls;
+ Button* b;
+ Label* l;
+
+ vpacker = manage (new VBox);
+ vpacker->set_spacing (6);
+ vpacker->set_border_width (12);
+
+ l = manage (new Label (string_compose (("<span size=\"larger\" weight=\"bold\">%1: %2</span>"), _("MIDI Channel Control"), track->name())));
+ l->set_use_markup (true);
+ l->set_alignment (0.5, 0.0);
+
+ vpacker->pack_start (*l, true, true);
+
+ l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Inbound"))));
+ l->set_use_markup (true);
+ vpacker->pack_start (*l);
+
+
+ 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));
+
+ 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_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_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_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_controls);
+
+ l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Playback"))));
+ l->set_use_markup (true);
+ vpacker->pack_start (*l);
+
+ 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));
+
+ vpacker->pack_start (playback_mask_box);
+
+ 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_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_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_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_controls);
+
+ add (*vpacker);
+}
+
+void
+MidiChannelSelectorWindow::fill_playback_mask ()
+{
+ if (track->get_playback_channel_mode() == FilterChannels) {
+ track->set_playback_channel_mask (0xffff);
+ }