summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-03-27 21:50:18 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2013-03-27 21:50:18 -0400
commit4abbabdcf9c6d6d98ba261d91846577a2fa2f05e (patch)
tree5a7134ccc9508a6f1da25ef3dc6d432bdc25a04f /gtk2_ardour
parent78aa7a13fd5e5abac70637ce6641b7d2e73dd541 (diff)
Squashed commit of the following:
commit fdbae82077db53add90df7448a06869dac89acc6 Author: Paul Davis <paul@linuxaudiosystems.com> Date: Wed Mar 27 21:45:28 2013 -0400 mammoth changes in basic signal flow, total redesign of MIDI channel filtering and more. commit 59343a8283698e02bc0f622313b29e98f449e4c8 Author: Paul Davis <paul@linuxaudiosystems.com> Date: Wed Mar 27 01:58:53 2013 -0400 initial working version after changes to MIDI channel filtering. may affect metering input too. testing not yet finished this commit merges many deep changes in ardour's internal architecture, combined with a total redesign of how MIDI channel filtering works. data in a track used to flow from JACK port buffers to diskstream's ringbuffers and was then copied from the ringbuffers into a BufferSet for use during Route::process_output_buffers(). The butler thread would handle the movement of data between the ringbuffers and disk. with this commit, data now flows from JACK port buffers into the BufferSet used for Route processing, and is copied from the BufferSet into the diskstream's ringbuffers (the butler thread continues to handle interactions with disk as usual). this change allowed a dramatic consolidation of code and simplification of most aspects of Track/Route::roll() and Track/Route::no_roll(). in particular, see Route::fill_buffers_with_input() which now concisely describes how we move data from JACK port buffers into the BufferSet for all Route types (including Tracks). this work was initially motivated by changing MIDI channel filtering so that we can process capture and playback independently. there is now a very clean pathway for this - see MidiTrack::roll() (NOTE: This needs implementing in the no-roll case too - a TODO item). the channel selector for MIDI tracks has been moved out of the track header and is now accessible via the context menu. more work is likely here, to make it (more) obvious to the user when filtering is going on.
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/canvas-note-event.cc1
-rw-r--r--gtk2_ardour/midi_channel_selector.cc378
-rw-r--r--gtk2_ardour/midi_channel_selector.h60
-rw-r--r--gtk2_ardour/midi_region_view.cc66
-rw-r--r--gtk2_ardour/midi_region_view.h9
-rw-r--r--gtk2_ardour/midi_time_axis.cc96
-rw-r--r--gtk2_ardour/midi_time_axis.h12
-rw-r--r--gtk2_ardour/route_time_axis.cc4
8 files changed, 535 insertions, 91 deletions
diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc
index 94b675b224..867e3cdf1c 100644
--- a/gtk2_ardour/canvas-note-event.cc
+++ b/gtk2_ardour/canvas-note-event.cc
@@ -22,6 +22,7 @@
#include "gtkmm2ext/keyboard.h"
#include "canvas-note-event.h"
+#include "midi_channel_selector.h"
#include "midi_region_view.h"
#include "public_editor.h"
#include "editing_syms.h"
diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc
index 6770f0e60d..aea9d31f03 100644
--- a/gtk2_ardour/midi_channel_selector.cc
+++ b/gtk2_ardour/midi_channel_selector.cc
@@ -19,12 +19,25 @@
#include <algorithm>
#include <sstream>
+#include <gtkmm/separator.h>
+#include <gtkmm/box.h>
+#include <gtkmm/label.h>
+#include <gtkmm/togglebutton.h>
+#include <gtkmm/radiobutton.h>
+#include <gtkmm/table.h>
+
+#include "pbd/compose.h"
+
+#include "gtkmm2ext/gtk_ui.h"
+#include "gtkmm2ext/gui_thread.h"
+
+#include "ardour/midi_track.h"
#include "midi_channel_selector.h"
-#include "gtkmm/separator.h"
-#include "i18n.h"
#include "rgb_macros.h"
+#include "i18n.h"
+
using namespace std;
using namespace Gtk;
using namespace ARDOUR;
@@ -310,3 +323,364 @@ MidiMultipleChannelSelector::invert_selection(void)
mode_changed.emit(_channel_mode, get_selected_channels());
}
+/*-----------------------------------------*/
+
+MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrack> mt)
+ : ArdourWindow (string_compose (_("MIDI Channel Control for %1"), mt->name()))
+ , track (mt)
+{
+ build ();
+
+ playback_mask_changed ();
+ playback_mode_changed ();
+ capture_mask_changed ();
+ capture_mode_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());
+ track->CaptureChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
+}
+
+MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
+{
+}
+
+void
+MidiChannelSelectorWindow::build ()
+{
+ VBox* vpacker;
+ HBox* capture_mask;
+ HBox* capture_mask_controls;
+ HBox* playback_mask;
+ HBox* playback_mask_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 ("<span size=\"large\" weight=\"bold\">%1</span>", _("Capture"))));
+ l->set_use_markup (true);
+ vpacker->pack_start (*l);
+
+ {
+ RadioButtonGroup group;
+
+ 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));
+
+ 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);
+
+ 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);
+
+ capture_mask_controls = manage (new HBox);
+ capture_mask_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);
+ 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);
+ 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);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_capture_mask));
+
+ vpacker->pack_start (*capture_mask_controls);
+
+ playback_mask = manage (new HBox);
+
+ l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("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));
+
+ 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));
+ }
+
+ 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);
+
+ b = manage (new Button (_("All")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable playback of all channels"));
+ playback_mask_controls->pack_start (*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);
+ 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);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_playback_mask));
+
+ vpacker->pack_start (*playback_mask_controls);
+
+ add (*vpacker);
+}
+
+void
+MidiChannelSelectorWindow::fill_playback_mask ()
+{
+ track->set_playback_channel_mask (0xffff);
+}
+
+void
+MidiChannelSelectorWindow::zero_playback_mask ()
+{
+ track->set_playback_channel_mask (0);
+}
+
+void
+MidiChannelSelectorWindow::invert_playback_mask ()
+{
+ track->set_playback_channel_mask (~track->get_playback_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::fill_capture_mask ()
+{
+ track->set_capture_channel_mask (0xffff);
+}
+
+void
+MidiChannelSelectorWindow::zero_capture_mask ()
+{
+ track->set_capture_channel_mask (0);
+}
+
+void
+MidiChannelSelectorWindow::invert_capture_mask ()
+{
+ 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<<i) & mask);
+ }
+}
+
+void
+MidiChannelSelectorWindow::set_capture_selected_channels (uint16_t mask)
+{
+ for (uint16_t i = 0; i < 16; i++) {
+ capture_buttons[i]->set_active ((1<<i) & mask);
+ }
+}
+
+void
+MidiChannelSelectorWindow::playback_mask_changed ()
+{
+ set_playback_selected_channels (track->get_playback_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::capture_mask_changed ()
+{
+ set_capture_selected_channels (track->get_capture_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::playback_mode_changed ()
+{
+ switch (track->get_playback_channel_mode()) {
+ case AllChannels:
+ playback_all_button->set_active ();
+ break;
+ case FilterChannels:
+ playback_filter_button->set_active ();
+ break;
+ case ForceChannel:
+ playback_force_button->set_active ();
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::capture_mode_changed ()
+{
+ switch (track->get_capture_channel_mode()) {
+ case AllChannels:
+ capture_all_button->set_active ();
+ break;
+ case FilterChannels:
+ capture_filter_button->set_active ();
+ break;
+ case ForceChannel:
+ capture_force_button->set_active ();
+ break;
+ }
+}
+
+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<<n));
+ } else {
+ track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<<n));
+ }
+}
+
+void
+MidiChannelSelectorWindow::capture_channel_clicked (uint16_t n)
+{
+ if (capture_buttons[n]->get_active()) {
+ track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<<n));
+ } else {
+ track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<<n));
+ }
+}
+
+void
+MidiChannelSelectorWindow::capture_mode_toggled (ChannelMode mode)
+{
+ /* this is called twice for every radio button change. the first time
+ 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.
+ */
+
+ switch (mode) {
+ case AllChannels:
+ if (!capture_all_button->get_active()) {
+ return;
+ }
+ track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask());
+ break;
+ case FilterChannels:
+ if (!capture_filter_button->get_active()) {
+ return;
+ }
+ track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask());
+ break;
+ case ForceChannel:
+ if (!capture_force_button->get_active()) {
+ return;
+ }
+ track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask());
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::playback_mode_toggled (ChannelMode mode)
+{
+ /* this is called twice for every radio button change. the first time
+ 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.
+ */
+
+ switch (mode) {
+ case AllChannels:
+ if (!playback_all_button->get_active()) {
+ return;
+ }
+ track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask());
+ break;
+ case FilterChannels:
+ if (!playback_filter_button->get_active()) {
+ return;
+ }
+ track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask());
+ break;
+ case ForceChannel:
+ if (!playback_force_button->get_active()) {
+ return;
+ }
+ track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask());
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::set_channel_colors (const uint32_t new_channel_colors[16])
+{
+ for (uint32_t n = 0; n < 16; ++n) {
+
+ char color_normal[8];
+ char color_active[8];
+
+ snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[n], 0x000000ff, 0.6));
+ snprintf(color_active, 8, "#%x", new_channel_colors[n]);
+
+ playback_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
+ playback_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
+
+ capture_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
+ capture_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
+ }
+}
+
+void
+MidiChannelSelectorWindow::set_default_channel_color()
+{
+ for (uint32_t n = 0; n < 16; ++n) {
+ playback_buttons[n]->unset_fg (STATE_NORMAL);
+ playback_buttons[n]->unset_bg (STATE_NORMAL);
+ playback_buttons[n]->unset_fg (STATE_ACTIVE);
+ playback_buttons[n]->unset_bg (STATE_ACTIVE);
+
+ capture_buttons[n]->unset_fg (STATE_NORMAL);
+ capture_buttons[n]->unset_bg (STATE_NORMAL);
+ capture_buttons[n]->unset_fg (STATE_ACTIVE);
+ capture_buttons[n]->unset_bg (STATE_ACTIVE);
+ }
+}
diff --git a/gtk2_ardour/midi_channel_selector.h b/gtk2_ardour/midi_channel_selector.h
index 5764a8d813..f6d3206c31 100644
--- a/gtk2_ardour/midi_channel_selector.h
+++ b/gtk2_ardour/midi_channel_selector.h
@@ -26,11 +26,18 @@
#include "gtkmm/table.h"
#include "gtkmm/button.h"
+#include "gtkmm/radiobutton.h"
#include "gtkmm/label.h"
#include "gtkmm2ext/stateful_button.h"
#include "ardour/types.h"
+#include "ardour_window.h"
+
+namespace ARDOUR {
+ class MidiTrack;
+}
+
class MidiChannelSelector : public Gtk::Table
{
public:
@@ -108,4 +115,57 @@ protected:
Gtk::ToggleButton _force_channel;
};
+class MidiChannelSelectorWindow : public ArdourWindow, public PBD::ScopedConnectionList
+{
+ public:
+ MidiChannelSelectorWindow (boost::shared_ptr<ARDOUR::MidiTrack>);
+ ~MidiChannelSelectorWindow ();
+
+ void set_channel_colors (const uint32_t new_channel_colors[16]);
+ void set_default_channel_color();
+
+ private:
+ boost::shared_ptr<ARDOUR::MidiTrack> track;
+ std::vector<Gtk::ToggleButton*> playback_buttons;
+ std::vector<Gtk::ToggleButton*> 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;
+
+ void build();
+ void set_capture_selected_channels (uint16_t);
+ void set_playback_selected_channels (uint16_t);
+
+ void fill_playback_mask ();
+ void zero_playback_mask ();
+ void invert_playback_mask ();
+
+ void fill_capture_mask ();
+ void zero_capture_mask ();
+ void invert_capture_mask ();
+
+ void playback_mask_changed ();
+ void capture_mask_changed ();
+ void playback_mode_changed ();
+ void capture_mode_changed ();
+
+ void playback_channel_clicked (uint16_t);
+ void capture_channel_clicked (uint16_t);
+
+ void playback_all_clicked();
+ void playback_none_clicked();
+ void playback_invert_clicked();
+
+ void capture_all_clicked();
+ void capture_none_clicked();
+ void capture_invert_clicked();
+
+ void capture_mode_toggled (ARDOUR::ChannelMode);
+ void playback_mode_toggled (ARDOUR::ChannelMode);
+};
+
#endif /*__ardour_ui_midi_channel_selector_h__*/
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 81e5cf23e9..d6b6935e11 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -66,6 +66,7 @@
#include "mouse_cursors.h"
#include "note_player.h"
#include "public_editor.h"
+#include "route_time_axis.h"
#include "rgb_macros.h"
#include "selection.h"
#include "simpleline.h"
@@ -89,7 +90,6 @@ PBD::Signal1<void, MidiRegionView *> MidiRegionView::SelectionCleared;
MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv,
boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color const & basic_color)
: RegionView (parent, tv, r, spu, basic_color)
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -116,13 +116,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
_note_group->raise_to_top();
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
-
- MidiTimeAxisView *time_axis = dynamic_cast<MidiTimeAxisView *>(&tv);
- if (time_axis) {
- _last_channel_mode = time_axis->channel_selector().get_channel_mode();
- _last_channel_selection = time_axis->channel_selector().get_selected_channels();
- }
-
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
connect_to_diskstream ();
@@ -133,7 +126,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color,
TimeAxisViewItem::Visibility visibility)
: RegionView (parent, tv, r, spu, basic_color, false, visibility)
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -160,12 +152,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
_note_group->raise_to_top();
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
- MidiTimeAxisView *time_axis = dynamic_cast<MidiTimeAxisView *>(&tv);
- if (time_axis) {
- _last_channel_mode = time_axis->channel_selector().get_channel_mode();
- _last_channel_selection = time_axis->channel_selector().get_selected_channels();
- }
-
connect_to_diskstream ();
SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
@@ -184,7 +170,6 @@ MidiRegionView::parameter_changed (std::string const & p)
MidiRegionView::MidiRegionView (const MidiRegionView& other)
: sigc::trackable(other)
, RegionView (other)
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -219,7 +204,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<MidiRegion> region)
: RegionView (other, boost::shared_ptr<Region> (region))
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -293,8 +277,10 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
group->raise_to_top();
group->signal_event().connect (sigc::mem_fun (this, &MidiRegionView::canvas_event), false);
- midi_view()->signal_channel_mode_changed().connect(
- sigc::mem_fun(this, &MidiRegionView::midi_channel_mode_changed));
+
+ midi_view()->midi_track()->PlaybackChannelModeChanged.connect (_channel_mode_changed_connection, invalidator (*this),
+ boost::bind (&MidiRegionView::midi_channel_mode_changed, this),
+ gui_context ());
instrument_info().Changed.connect (_instrument_changed_connection, invalidator (*this),
boost::bind (&MidiRegionView::instrument_settings_changed, this), gui_context());
@@ -1214,7 +1200,7 @@ void
MidiRegionView::display_patch_changes ()
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+ uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
for (uint8_t i = 0; i < 16; ++i) {
display_patch_changes_on_channel (i, chn_mask & (1 << i));
@@ -1673,7 +1659,7 @@ MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
/* outline all edges */
ev->property_outline_what() = (guint32) 0xF;
}
-
+
if (update_ghost_regions) {
for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
@@ -1751,7 +1737,7 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note, bool visible)
event->show_velocity();
}
- event->on_channel_selection_change(_last_channel_selection);
+ event->on_channel_selection_change (get_selected_channels());
_events.push_back(event);
if (visible) {
@@ -3220,20 +3206,21 @@ MidiRegionView::set_frame_color()
}
void
-MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
+MidiRegionView::midi_channel_mode_changed ()
{
+ MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ uint16_t mask = mtv->midi_track()->get_playback_channel_mask();
+ ChannelMode mode = mtv->midi_track()->get_playback_channel_mode ();
+
if (mode == ForceChannel) {
mask = 0xFFFF; // Show all notes as active (below)
}
// Update notes for selection
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->on_channel_selection_change(mask);
+ (*i)->on_channel_selection_change (mask);
}
- _last_channel_selection = mask;
- _last_channel_mode = mode;
-
_patch_changes.clear ();
display_patch_changes ();
}
@@ -3399,7 +3386,7 @@ MidiRegionView::goto_next_note (bool add_to_selection)
time_sort_events ();
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+ uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
if ((*i)->selected()) {
@@ -3436,7 +3423,7 @@ MidiRegionView::goto_previous_note (bool add_to_selection)
time_sort_events ();
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+ uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask ();
for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
if ((*i)->selected()) {
@@ -3562,7 +3549,7 @@ MidiRegionView::maybe_select_by_position (GdkEventButton* ev, double /*x*/, doub
Events e;
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+ uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
get_events (e, Evoral::Sequence<Evoral::MusicalTime>::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask);
@@ -3687,8 +3674,8 @@ MidiRegionView::data_recorded (boost::weak_ptr<MidiSource> w)
Evoral::MIDIEvent<MidiBuffer::TimeType> const ev (*i, false);
if (ev.is_channel_event()) {
- if (_last_channel_mode == FilterChannels) {
- if (((uint16_t(1) << ev.channel()) & _last_channel_selection) == 0) {
+ if (get_channel_mode() == FilterChannels) {
+ if (((uint16_t(1) << ev.channel()) & get_selected_channels()) == 0) {
continue;
}
}
@@ -3883,3 +3870,18 @@ MidiRegionView::note_button_release ()
delete _note_player;
_note_player = 0;
}
+
+ChannelMode
+MidiRegionView::get_channel_mode () const
+{
+ RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (&trackview);
+ return rtav->midi_track()->get_playback_channel_mode();
+}
+
+uint16_t
+MidiRegionView::get_selected_channels () const
+{
+ RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (&trackview);
+ return rtav->midi_track()->get_playback_channel_mask();
+}
+
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 689e0ab2d0..5f374da55c 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -355,7 +355,8 @@ private:
bool canvas_event(GdkEvent* ev);
bool note_canvas_event(GdkEvent* ev);
- void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
+ void midi_channel_mode_changed ();
+ PBD::ScopedConnection _channel_mode_changed_connection;
void instrument_settings_changed ();
PBD::ScopedConnection _instrument_changed_connection;
@@ -377,9 +378,6 @@ private:
void show_verbose_cursor (std::string const &, double, double) const;
void show_verbose_cursor (boost::shared_ptr<NoteType>) const;
- ARDOUR::ChannelMode _last_channel_mode;
- uint16_t _last_channel_selection;
-
uint8_t _current_range_min;
uint8_t _current_range_max;
@@ -480,6 +478,9 @@ private:
Gdk::Cursor* pre_press_cursor;
NotePlayer* _note_player;
+
+ ARDOUR::ChannelMode get_channel_mode() const;
+ uint16_t get_selected_channels () const;
};
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 9fe3a77450..6c284fa0a0 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -66,6 +66,7 @@
#include "ghostregion.h"
#include "gui_thread.h"
#include "keyboard.h"
+#include "midi_channel_selector.h"
#include "midi_scroomer.h"
#include "midi_streamview.h"
#include "midi_region_view.h"
@@ -94,8 +95,8 @@ using namespace Gtkmm2ext;
using namespace Editing;
// Minimum height at which a control is displayed
-static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
-static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
+static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 130;
+static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
: AxisView(sess) // virtually inherited
@@ -110,6 +111,7 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& can
, _meter_color_mode_item(0)
, _channel_color_mode_item(0)
, _track_color_mode_item(0)
+ , _channel_selector (0)
, _step_edit_item (0)
, controller_menu (0)
, _step_editor (0)
@@ -246,28 +248,19 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
_midi_controls_box.set_border_width (10);
if (!patch_manager.all_models().empty()) {
- _channel_selector.set_border_width(2);
- _channel_selector.show_all ();
-
- _midi_controls_box.resize(3, 2);
- _midi_controls_box.attach(_channel_selector, 0, 2, 0, 1);
-
- _midi_controls_box.attach(*manage(new HSeparator()), 0, 2, 1, 2);
+ _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, 2, 3);
+ _midi_controls_box.attach(_midnam_model_selector, 0, 1, 0, 1);
_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, 3, 4);
- } else {
- _midi_controls_box.attach(_channel_selector, 0, 1, 0, 1);
- _channel_selector.show_all ();
- }
+ _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 1, 2);
+ }
model_changed();
custom_device_mode_changed();
@@ -279,19 +272,11 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
controls_vbox.pack_start(_midi_controls_box, false, false);
- // restore channel selector settings
- _channel_selector.set_channel_mode(midi_track()->get_channel_mode(),
- midi_track()->get_channel_mask());
- _channel_selector.mode_changed.connect(
- sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
- _channel_selector.mode_changed.connect(
- sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
-
const string color_mode = gui_property ("color-mode");
if (!color_mode.empty()) {
_color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
- if (_color_mode == ChannelColors) {
- _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ if (_channel_selector && _color_mode == ChannelColors) {
+ _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
}
}
@@ -334,6 +319,8 @@ MidiTimeAxisView::first_idle ()
MidiTimeAxisView::~MidiTimeAxisView ()
{
+ delete _channel_selector;
+
delete _piano_roll_header;
_piano_roll_header = 0;
@@ -468,11 +455,36 @@ MidiTimeAxisView::append_extra_display_menu_items ()
items.push_back (MenuElem (_("Note Range"), *range_menu));
items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
+ items.push_back (MenuElem (_("Channel Selector"),
+ sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
+ color_mode_menu = build_color_mode_menu();
+ if (color_mode_menu) {
+ items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
+ }
+
items.push_back (SeparatorElem ());
}
void
+MidiTimeAxisView::toggle_channel_selector ()
+{
+ if (!_channel_selector) {
+ _channel_selector = new MidiChannelSelectorWindow (midi_track());
+
+ if (_color_mode == ChannelColors) {
+ _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ } else {
+ _channel_selector->set_default_channel_color ();
+ }
+
+ _channel_selector->show_all ();
+ } else {
+ _channel_selector->cycle_visibility ();
+ }
+}
+
+void
MidiTimeAxisView::build_automation_action_menu (bool for_selection)
{
using namespace Menu_Helpers;
@@ -493,7 +505,7 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection)
MenuList& automation_items = automation_action_menu->items();
- uint16_t selected_channels = _channel_selector.get_selected_channels();
+ uint16_t selected_channels = midi_track()->get_playback_channel_mask();
if (selected_channels != 0) {
@@ -537,7 +549,7 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection)
void
MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
{
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
@@ -564,7 +576,7 @@ MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
structure if there is more than 1 selected.
*/
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
int chn_cnt = 0;
for (uint8_t chn = 0; chn < 16; chn++) {
@@ -665,7 +677,7 @@ MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl
{
using namespace Menu_Helpers;
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
@@ -706,7 +718,7 @@ MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_
{
using namespace Menu_Helpers;
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
Menu* chn_menu = manage (new Menu);
MenuList& chn_items (chn_menu->items());
@@ -804,7 +816,7 @@ MidiTimeAxisView::build_controller_menu ()
combination covering the currently selected channels for this track
*/
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
/* count the number of selected channels because we will build a different menu
structure if there is more than 1 selected.
@@ -982,10 +994,12 @@ MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bo
return;
}
- if (mode == ChannelColors) {
- _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
- } else {
- _channel_selector.set_default_channel_color();
+ if (_channel_selector) {
+ if (mode == ChannelColors) {
+ _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ } else {
+ _channel_selector->set_default_channel_color();
+ }
}
_color_mode = mode;
@@ -1168,7 +1182,7 @@ MidiTimeAxisView::set_note_selection (uint8_t note)
return;
}
- uint16_t chn_mask = _channel_selector.get_selected_channels();
+ uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1188,7 +1202,7 @@ MidiTimeAxisView::add_note_selection (uint8_t note)
return;
}
- const uint16_t chn_mask = _channel_selector.get_selected_channels();
+ const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1208,7 +1222,7 @@ MidiTimeAxisView::extend_note_selection (uint8_t note)
return;
}
- const uint16_t chn_mask = _channel_selector.get_selected_channels();
+ const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1228,7 +1242,7 @@ MidiTimeAxisView::toggle_note_selection (uint8_t note)
return;
}
- const uint16_t chn_mask = _channel_selector.get_selected_channels();
+ const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1272,7 +1286,7 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
the right ones.
*/
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
bool changed = false;
no_redraw = true;
@@ -1392,7 +1406,7 @@ MidiTimeAxisView::stop_step_editing ()
uint8_t
MidiTimeAxisView::get_channel_for_add () const
{
- uint16_t const chn_mask = _channel_selector.get_selected_channels ();
+ uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
int chn_cnt = 0;
uint8_t channel = 0;
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index 1f179baca6..e5fccd8c2f 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -39,7 +39,6 @@
#include "route_time_axis.h"
#include "canvas.h"
#include "midi_streamview.h"
-#include "midi_channel_selector.h"
namespace MIDI {
namespace Name {
@@ -62,6 +61,7 @@ class MidiScroomer;
class PianoRollHeader;
class StepEntry;
class StepEditor;
+class MidiChannelSelectorWindow;
class MidiTimeAxisView : public RouteTimeAxisView
{
@@ -92,12 +92,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
void update_range();
- sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed() {
- return _channel_selector.mode_changed;
- }
-
- const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
-
Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
StepEditor* step_editor() { return _step_editor; }
@@ -141,7 +135,7 @@ class MidiTimeAxisView : public RouteTimeAxisView
Gtk::RadioMenuItem* _channel_color_mode_item;
Gtk::RadioMenuItem* _track_color_mode_item;
Gtk::Table _midi_controls_box;
- MidiMultipleChannelSelector _channel_selector;
+ MidiChannelSelectorWindow* _channel_selector;
Gtk::ComboBoxText _midnam_model_selector;
Gtk::ComboBoxText _midnam_custom_device_mode_selector;
@@ -157,6 +151,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
void add_single_channel_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name);
void add_multi_channel_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name);
void build_controller_menu ();
+ void toggle_channel_selector ();
+ void channel_selector_hidden ();
void set_channel_mode (ARDOUR::ChannelMode, uint16_t);
void set_note_selection (uint8_t note);
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 041cbb59e1..784203bf6f 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -639,10 +639,6 @@ RouteTimeAxisView::build_display_menu ()
items.push_back (MenuElem (_("Mode"), *mode_menu));
}
- color_mode_menu = build_color_mode_menu();
- if (color_mode_menu) {
- items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
- }
items.push_back (SeparatorElem());