From f1ce235b6bc10a336822a052cee517fa923def48 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 28 Mar 2013 17:10:57 -0400 Subject: [PATCH] some deep tweaking to get MIDI channel control into nearly done shape for 3.1 --- gtk2_ardour/midi_channel_selector.cc | 451 +++++++++++++++++++-------- gtk2_ardour/midi_channel_selector.h | 136 ++++---- gtk2_ardour/midi_time_axis.cc | 77 ++++- gtk2_ardour/midi_time_axis.h | 9 +- 4 files changed, 482 insertions(+), 191 deletions(-) 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; } } diff --git a/gtk2_ardour/midi_channel_selector.h b/gtk2_ardour/midi_channel_selector.h index f6d3206c31..f10c128b92 100644 --- a/gtk2_ardour/midi_channel_selector.h +++ b/gtk2_ardour/midi_channel_selector.h @@ -40,79 +40,79 @@ namespace ARDOUR { class MidiChannelSelector : public Gtk::Table { -public: - MidiChannelSelector(int n_rows = 4, int n_columns = 4, int start_row = 0, int start_column = 0); - virtual ~MidiChannelSelector() = 0; + public: + MidiChannelSelector(int n_rows = 4, int n_columns = 4, int start_row = 0, int start_column = 0); + virtual ~MidiChannelSelector() = 0; - sigc::signal clicked; + sigc::signal clicked; - void set_channel_colors(const uint32_t new_channel_colors[16]); - void set_default_channel_color(); + void set_channel_colors(const uint32_t new_channel_colors[16]); + void set_default_channel_color(); -protected: - virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr) = 0; - Gtk::Label _button_labels[4][4]; - Gtkmm2ext::StatefulToggleButton _buttons[4][4]; - int _recursion_counter; + protected: + virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr) = 0; + Gtk::Label _button_labels[4][4]; + Gtkmm2ext::StatefulToggleButton _buttons[4][4]; + int _recursion_counter; - bool was_clicked (GdkEventButton*); + bool was_clicked (GdkEventButton*); }; class SingleMidiChannelSelector : public MidiChannelSelector { -public: - SingleMidiChannelSelector(uint8_t active_channel = 0); + public: + SingleMidiChannelSelector(uint8_t active_channel = 0); - uint8_t get_active_channel() const { return _active_channel; } + uint8_t get_active_channel() const { return _active_channel; } - sigc::signal channel_selected; + sigc::signal channel_selected; -protected: - virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr); + protected: + virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr); - Gtk::ToggleButton* _last_active_button; - uint8_t _active_channel; + Gtk::ToggleButton* _last_active_button; + uint8_t _active_channel; }; class MidiMultipleChannelSelector : public MidiChannelSelector { -public: - MidiMultipleChannelSelector(ARDOUR::ChannelMode mode = ARDOUR::FilterChannels, - uint16_t initial_selection = 0xFFFF); - - virtual ~MidiMultipleChannelSelector(); - - /** The channel mode or selected channel(s) has changed. - * First parameter is the new channel mode, second parameter is a bitmask - * of the currently selected channels. - */ - sigc::signal mode_changed; - - void set_channel_mode(ARDOUR::ChannelMode mode, uint16_t mask); - ARDOUR::ChannelMode get_channel_mode () const { return _channel_mode; } - - /** - * @return each bit in the returned word represents a midi channel, eg. - * bit 0 represents channel 0 and bit 15 represents channel 15 - * - */ - uint16_t get_selected_channels() const; - void set_selected_channels(uint16_t selected_channels); - -protected: - ARDOUR::ChannelMode _channel_mode; - ARDOUR::NoteMode _note_mode; - - virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr); - void force_channels_button_toggled(); - - void select_all(bool on); - void invert_selection(void); - - Gtk::Button _select_all; - Gtk::Button _select_none; - Gtk::Button _invert_selection; - Gtk::ToggleButton _force_channel; + public: + MidiMultipleChannelSelector(ARDOUR::ChannelMode mode = ARDOUR::FilterChannels, + uint16_t initial_selection = 0xFFFF); + + virtual ~MidiMultipleChannelSelector(); + + /** The channel mode or selected channel(s) has changed. + * First parameter is the new channel mode, second parameter is a bitmask + * of the currently selected channels. + */ + sigc::signal mode_changed; + + void set_channel_mode(ARDOUR::ChannelMode mode, uint16_t mask); + ARDOUR::ChannelMode get_channel_mode () const { return _channel_mode; } + + /** + * @return each bit in the returned word represents a midi channel, eg. + * bit 0 represents channel 0 and bit 15 represents channel 15 + * + */ + uint16_t get_selected_channels() const; + void set_selected_channels(uint16_t selected_channels); + + protected: + ARDOUR::ChannelMode _channel_mode; + ARDOUR::NoteMode _note_mode; + + virtual void button_toggled(Gtk::ToggleButton* button, uint8_t button_nr); + void force_channels_button_toggled(); + + void select_all(bool on); + void invert_selection(void); + + Gtk::Button _select_all; + Gtk::Button _select_none; + Gtk::Button _invert_selection; + Gtk::ToggleButton _force_channel; }; class MidiChannelSelectorWindow : public ArdourWindow, public PBD::ScopedConnectionList @@ -129,12 +129,22 @@ class MidiChannelSelectorWindow : public ArdourWindow, public PBD::ScopedConnect std::vector playback_buttons; std::vector capture_buttons; - Gtk::ToggleButton* playback_all_button; - Gtk::ToggleButton* playback_filter_button; - Gtk::ToggleButton* playback_force_button; - Gtk::ToggleButton* capture_all_button; - Gtk::ToggleButton* capture_filter_button; - Gtk::ToggleButton* capture_force_button; + std::vector playback_mask_controls; + std::vector capture_mask_controls; + + Gtk::HBox capture_mask_box; + Gtk::HBox playback_mask_box; + Gtk::RadioButtonGroup playback_button_group; + Gtk::RadioButton playback_all_button; + Gtk::RadioButton playback_filter_button; + Gtk::RadioButton playback_force_button; + Gtk::RadioButtonGroup capture_button_group; + Gtk::RadioButton capture_all_button; + Gtk::RadioButton capture_filter_button; + Gtk::RadioButton capture_force_button; + + ARDOUR::ChannelMode last_drawn_capture_mode; + ARDOUR::ChannelMode last_drawn_playback_mode; void build(); void set_capture_selected_channels (uint16_t); diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index 6c284fa0a0..3b8e4932fb 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -19,6 +19,8 @@ #include #include +#include // for ffs(3) + #include #include #include @@ -95,7 +97,7 @@ using namespace Gtkmm2ext; using namespace Editing; // Minimum height at which a control is displayed -static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 130; +static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 140; static const uint32_t KEYBOARD_MIN_HEIGHT = 130; MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas) @@ -212,6 +214,22 @@ MidiTimeAxisView::set_route (boost::shared_ptr rt) _view->RegionViewAdded.connect ( sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added)); + midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this), + boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this), + gui_context()); + midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this), + boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this), + gui_context()); + midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this), + boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this), + gui_context()); + midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this), + boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this), + gui_context()); + + playback_channel_mode_changed (); + capture_channel_mode_changed (); + if (!_editor.have_idled()) { /* first idle will do what we need */ } else { @@ -247,19 +265,37 @@ MidiTimeAxisView::set_route (boost::shared_ptr rt) _midi_controls_box.set_homogeneous(false); _midi_controls_box.set_border_width (10); + _channel_status_box.set_homogeneous (false); + _channel_status_box.set_spacing (6); + + _channel_selector_button.set_label (_("Chns")); + + /* fixed sized labels to prevent silly nonsense */ + + _playback_channel_status.set_size_request (65, -1); + _capture_channel_status.set_size_request (60, -1); + + _channel_status_box.pack_start (_playback_channel_status, false, false); + _channel_status_box.pack_start (_capture_channel_status, false, false); + _channel_status_box.pack_start (_channel_selector_button, false, false); + _channel_status_box.show_all (); + + _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector)); + + _midi_controls_box.pack_start (_channel_status_box, false, false, 10); + if (!patch_manager.all_models().empty()) { - _midi_controls_box.resize(2, 2); _midnam_model_selector.set_size_request(22, 30); _midnam_model_selector.set_border_width(2); _midnam_model_selector.show (); - _midi_controls_box.attach(_midnam_model_selector, 0, 1, 0, 1); + _midi_controls_box.pack_start (_midnam_model_selector); _midnam_custom_device_mode_selector.set_size_request(10, 30); _midnam_custom_device_mode_selector.set_border_width(2); _midnam_custom_device_mode_selector.show (); - _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 1, 2); + _midi_controls_box.pack_start (_midnam_custom_device_mode_selector); } model_changed(); @@ -478,6 +514,7 @@ MidiTimeAxisView::toggle_channel_selector () _channel_selector->set_default_channel_color (); } + _channel_selector->set_position (WIN_POS_MOUSE); _channel_selector->show_all (); } else { _channel_selector->cycle_visibility (); @@ -1440,3 +1477,35 @@ MidiTimeAxisView::contents_height_changed () { _range_scroomer->set_size_request (-1, _view->child_height ()); } + +void +MidiTimeAxisView::playback_channel_mode_changed () +{ + switch (midi_track()->get_playback_channel_mode()) { + case AllChannels: + _playback_channel_status.set_markup (string_compose ("%1: %2", _("Play"), ("all"))); + break; + case FilterChannels: + _playback_channel_status.set_markup (string_compose ("%1: %2", _("Play"), ("some"))); + break; + case ForceChannel: + _playback_channel_status.set_markup (string_compose ("%1: %2>%3", _("Play"), ("all"), ffs (midi_track()->get_playback_channel_mask()))); + break; + } +} + +void +MidiTimeAxisView::capture_channel_mode_changed () +{ + switch (midi_track()->get_capture_channel_mode()) { + case AllChannels: + _capture_channel_status.set_markup (string_compose ("%1: %2", _("Rec"), ("all"))); + break; + case FilterChannels: + _capture_channel_status.set_markup (string_compose ("%1: %2", _("Rec"), ("some"))); + break; + case ForceChannel: + _capture_channel_status.set_markup (string_compose ("%1: %2>%3", _("Rec"), ("all"), ffs (midi_track()->get_capture_channel_mask()))); + break; + } +} diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h index e5fccd8c2f..25e89fc2e0 100644 --- a/gtk2_ardour/midi_time_axis.h +++ b/gtk2_ardour/midi_time_axis.h @@ -134,7 +134,11 @@ class MidiTimeAxisView : public RouteTimeAxisView Gtk::RadioMenuItem* _meter_color_mode_item; Gtk::RadioMenuItem* _channel_color_mode_item; Gtk::RadioMenuItem* _track_color_mode_item; - Gtk::Table _midi_controls_box; + Gtk::Label _playback_channel_status; + Gtk::Label _capture_channel_status; + Gtk::HBox _channel_status_box; + Gtk::Button _channel_selector_button; + Gtk::VBox _midi_controls_box; MidiChannelSelectorWindow* _channel_selector; Gtk::ComboBoxText _midnam_model_selector; Gtk::ComboBoxText _midnam_custom_device_mode_selector; @@ -172,6 +176,9 @@ class MidiTimeAxisView : public RouteTimeAxisView ParameterMenuMap _controller_menu_map; StepEditor* _step_editor; + + void capture_channel_mode_changed(); + void playback_channel_mode_changed(); }; #endif /* __ardour_midi_time_axis_h__ */ -- 2.30.2