2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/profile.h"
54 #include "ardour/region.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_object.h"
59 #include "ardour/source.h"
60 #include "ardour/track.h"
61 #include "ardour/types.h"
63 #include "ardour_ui.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
88 #include "note_base.h"
90 #include "ardour/midi_track.h"
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
101 // Minimum height at which a control is displayed
102 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
103 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
105 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
106 : AxisView(sess) // virtually inherited
107 , RouteTimeAxisView(ed, sess, canvas)
108 , _ignore_signals(false)
110 , _piano_roll_header(0)
111 , _note_mode(Sustained)
113 , _percussion_mode_item(0)
114 , _color_mode(MeterColors)
115 , _meter_color_mode_item(0)
116 , _channel_color_mode_item(0)
117 , _track_color_mode_item(0)
118 , _channel_selector (0)
119 , _step_edit_item (0)
120 , controller_menu (0)
126 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
130 _view = new MidiStreamView (*this);
133 _piano_roll_header = new PianoRollHeader(*midi_view());
134 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
135 _range_scroomer->DoubleClicked.connect (
136 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
137 MidiStreamView::ContentsRange, false));
140 /* This next call will result in our height being set up, so it must come after
141 the creation of the piano roll / range scroomer as their visibility is set up
144 RouteTimeAxisView::set_route (rt);
146 _view->apply_color (_color, StreamView::RegionColor);
148 subplugin_menu.set_name ("ArdourContextMenu");
150 if (!gui_property ("note-range-min").empty ()) {
151 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
152 atoi (gui_property ("note-range-max").c_str()),
156 midi_view()->NoteRangeChanged.connect (
157 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
158 _view->ContentsHeightChanged.connect (
159 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
161 ignore_toggle = false;
163 if (is_midi_track()) {
164 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
165 time_axis_frame.set_name ("MidiTimeAxisViewControlsBaseUnselected");
166 _note_mode = midi_track()->note_mode();
167 } else { // MIDI bus (which doesn't exist yet..)
168 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
169 time_axis_frame.set_name ("MidiBusControlsBaseUnselected");
172 /* if set_state above didn't create a gain automation child, we need to make one */
173 if (automation_child (GainAutomation) == 0) {
174 create_automation_child (GainAutomation, false);
177 /* if set_state above didn't create a mute automation child, we need to make one */
178 if (automation_child (MuteAutomation) == 0) {
179 create_automation_child (MuteAutomation, false);
182 if (_route->panner_shell()) {
183 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
186 /* map current state of the route */
187 ensure_pan_views (false);
189 processors_changed (RouteProcessorChange ());
191 _route->processors_changed.connect (*this, invalidator (*this),
192 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
196 _piano_roll_header->SetNoteSelection.connect (
197 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
198 _piano_roll_header->AddNoteSelection.connect (
199 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
200 _piano_roll_header->ExtendNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
202 _piano_roll_header->ToggleNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
205 /* Suspend updates of the StreamView during scroomer drags to speed things up */
206 _range_scroomer->DragStarting.connect (
207 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
208 _range_scroomer->DragFinishing.connect (
209 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
211 /* Put the scroomer and the keyboard in a VBox with a padding
212 label so that they can be reduced in height for stacked-view
216 HSeparator* separator = manage (new HSeparator());
217 separator->set_name("TrackSeparator");
218 separator->set_size_request(-1, 1);
221 VBox* v = manage (new VBox);
222 HBox* h = manage (new HBox);
223 h->pack_end (*_piano_roll_header);
224 h->pack_end (*_range_scroomer);
225 v->pack_start (*separator, false, false);
226 v->pack_start (*h, true, true);
229 top_hbox.remove(scroomer_placeholder);
230 time_axis_hbox.pack_end(*v, false, false, 0);
231 midi_scroomer_size_group->add_widget (*v);
233 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
234 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
235 controls_base_selected_name = "MidiTrackControlsBaseSelected";
236 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
238 midi_view()->NoteRangeChanged.connect (
239 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
241 /* ask for notifications of any new RegionViews */
242 _view->RegionViewAdded.connect (
243 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
245 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
246 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
248 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
249 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
251 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
252 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
254 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
255 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
258 playback_channel_mode_changed ();
259 capture_channel_mode_changed ();
261 if (!_editor.have_idled()) {
262 /* first idle will do what we need */
268 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
270 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
271 for (; m != patch_manager.all_models().end(); ++m) {
272 _midnam_model_selector.append_text(m->c_str());
275 if (gui_property (X_("midnam-model-name")).empty()) {
276 set_gui_property (X_("midnam-model-name"), "Generic");
279 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
280 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
282 set_gui_property (X_("midnam-custom-device-mode"),
283 *device_names->custom_device_mode_names().begin());
287 _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
288 _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
290 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
291 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
293 _midi_controls_box.set_homogeneous(false);
294 _midi_controls_box.set_border_width (2);
296 _channel_status_box.set_homogeneous (false);
297 _channel_status_box.set_spacing (4);
299 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
300 channel_selector_button->set_name ("route button");
301 ARDOUR_UI::instance()->set_tip (channel_selector_button, _("Click to edit channel settings"));
303 /* fixed sized labels to prevent silly nonsense (though obviously,
304 * they cause their own too)
306 set_size_request_to_display_given_text(_playback_channel_status, "Play: somemo", 2, 2); // TODO use _("Play: all/some")
307 set_size_request_to_display_given_text(_capture_channel_status, "Rec: somemo", 2, 2); // TODO use _("Rec: all/some")
309 _channel_status_box.pack_start (_playback_channel_status, false, false);
310 _channel_status_box.pack_start (_capture_channel_status, false, false);
311 _channel_status_box.pack_end (*channel_selector_button, false, false);
312 _channel_status_box.show_all ();
314 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
316 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
318 if (!patch_manager.all_models().empty()) {
320 _midnam_model_selector.show ();
321 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
323 _midnam_custom_device_mode_selector.show ();
325 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
329 custom_device_mode_changed();
331 _midnam_model_selector.signal_changed().connect(
332 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
333 _midnam_custom_device_mode_selector.signal_changed().connect(
334 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
336 controls_vbox.pack_start(_midi_controls_box, false, false);
338 const string color_mode = gui_property ("color-mode");
339 if (!color_mode.empty()) {
340 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
341 if (_channel_selector && _color_mode == ChannelColors) {
342 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
346 set_color_mode (_color_mode, true, false);
348 const string note_mode = gui_property ("note-mode");
349 if (!note_mode.empty()) {
350 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
351 if (_percussion_mode_item) {
352 _percussion_mode_item->set_active (_note_mode == Percussive);
356 /* Look for any GUI object state nodes that represent automation children
357 * that should exist, and create the children.
360 const list<string> gui_ids = gui_object_state().all_ids ();
361 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
364 Evoral::Parameter parameter (0, 0, 0);
366 bool const p = AutomationTimeAxisView::parse_state_id (
367 *i, route_id, has_parameter, parameter);
368 if (p && route_id == _route->id () && has_parameter) {
369 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
370 create_automation_child (parameter, string_is_affirmative (visible));
376 MidiTimeAxisView::first_idle ()
383 MidiTimeAxisView::~MidiTimeAxisView ()
385 delete _channel_selector;
387 delete _piano_roll_header;
388 _piano_roll_header = 0;
390 delete _range_scroomer;
393 delete controller_menu;
398 MidiTimeAxisView::enter_internal_edit_mode ()
401 midi_view()->enter_internal_edit_mode ();
406 MidiTimeAxisView::leave_internal_edit_mode ()
409 midi_view()->leave_internal_edit_mode ();
414 MidiTimeAxisView::check_step_edit ()
416 ensure_step_editor ();
417 _step_editor->check_step_edit ();
421 MidiTimeAxisView::model_changed()
423 const Glib::ustring model = _midnam_model_selector.get_active_text();
424 set_gui_property (X_("midnam-model-name"), model);
426 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
427 .custom_device_mode_names_by_model(model);
429 _midnam_custom_device_mode_selector.clear_items();
431 for (std::list<std::string>::const_iterator i = device_modes.begin();
432 i != device_modes.end(); ++i) {
433 _midnam_custom_device_mode_selector.append_text(*i);
436 _midnam_custom_device_mode_selector.set_active(0);
438 _route->instrument_info().set_external_instrument (
439 _midnam_model_selector.get_active_text(),
440 _midnam_custom_device_mode_selector.get_active_text());
442 // Rebuild controller menu
443 _controller_menu_map.clear ();
444 delete controller_menu;
446 build_automation_action_menu(false);
450 MidiTimeAxisView::custom_device_mode_changed()
452 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
453 set_gui_property (X_("midnam-custom-device-mode"), mode);
454 _route->instrument_info().set_external_instrument (
455 _midnam_model_selector.get_active_text(), mode);
459 MidiTimeAxisView::midi_view()
461 return dynamic_cast<MidiStreamView*>(_view);
465 MidiTimeAxisView::set_height (uint32_t h)
467 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
468 _midi_controls_box.show ();
470 _midi_controls_box.hide();
473 if (h >= KEYBOARD_MIN_HEIGHT) {
474 if (is_track() && _range_scroomer) {
475 _range_scroomer->show();
477 if (is_track() && _piano_roll_header) {
478 _piano_roll_header->show();
481 if (is_track() && _range_scroomer) {
482 _range_scroomer->hide();
484 if (is_track() && _piano_roll_header) {
485 _piano_roll_header->hide();
489 /* We need to do this after changing visibility of our stuff, as it will
490 eventually trigger a call to Editor::reset_controls_layout_width(),
491 which needs to know if we have just shown or hidden a scroomer /
494 RouteTimeAxisView::set_height (h);
498 MidiTimeAxisView::append_extra_display_menu_items ()
500 using namespace Menu_Helpers;
502 MenuList& items = display_menu->items();
505 Menu *range_menu = manage(new Menu);
506 MenuList& range_items = range_menu->items();
507 range_menu->set_name ("ArdourContextMenu");
509 range_items.push_back (
510 MenuElem (_("Show Full Range"),
511 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
512 MidiStreamView::FullRange, true)));
514 range_items.push_back (
515 MenuElem (_("Fit Contents"),
516 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
517 MidiStreamView::ContentsRange, true)));
519 items.push_back (MenuElem (_("Note Range"), *range_menu));
520 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
521 items.push_back (MenuElem (_("Channel Selector"),
522 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
524 color_mode_menu = build_color_mode_menu();
525 if (color_mode_menu) {
526 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
529 items.push_back (SeparatorElem ());
533 MidiTimeAxisView::toggle_channel_selector ()
535 if (!_channel_selector) {
536 _channel_selector = new MidiChannelSelectorWindow (midi_track());
538 if (_color_mode == ChannelColors) {
539 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
541 _channel_selector->set_default_channel_color ();
544 _channel_selector->show_all ();
546 _channel_selector->cycle_visibility ();
551 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
553 using namespace Menu_Helpers;
555 /* If we have a controller menu, we need to detach it before
556 RouteTimeAxis::build_automation_action_menu destroys the
557 menu it is attached to. Otherwise GTK destroys
558 controller_menu's gobj, meaning that it can't be reattached
559 below. See bug #3134.
562 if (controller_menu) {
563 detach_menu (*controller_menu);
566 _channel_command_menu_map.clear ();
567 RouteTimeAxisView::build_automation_action_menu (for_selection);
569 MenuList& automation_items = automation_action_menu->items();
571 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
573 if (selected_channels != 0) {
575 automation_items.push_back (SeparatorElem());
577 /* these 2 MIDI "command" types are semantically more like automation
578 than note data, but they are not MIDI controllers. We give them
579 special status in this menu, since they will not show up in the
580 controller list and anyone who actually knows something about MIDI
581 (!) would not expect to find them there.
584 add_channel_command_menu_item (
585 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
586 automation_items.back().set_sensitive (
587 !for_selection || _editor.get_selection().tracks.size() == 1);
588 add_channel_command_menu_item (
589 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
590 automation_items.back().set_sensitive (
591 !for_selection || _editor.get_selection().tracks.size() == 1);
593 /* now all MIDI controllers. Always offer the possibility that we will
594 rebuild the controllers menu since it might need to be updated after
595 a channel mode change or other change. Also detach it first in case
596 it has been used anywhere else.
599 build_controller_menu ();
601 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
602 automation_items.back().set_sensitive (
603 !for_selection || _editor.get_selection().tracks.size() == 1);
605 automation_items.push_back (
606 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
607 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
612 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
614 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
616 for (uint8_t chn = 0; chn < 16; chn++) {
617 if (selected_channels & (0x0001 << chn)) {
619 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
620 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
623 menu->set_active (yn);
630 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
632 AutomationType auto_type,
635 using namespace Menu_Helpers;
637 /* count the number of selected channels because we will build a different menu
638 structure if there is more than 1 selected.
641 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
644 for (uint8_t chn = 0; chn < 16; chn++) {
645 if (selected_channels & (0x0001 << chn)) {
654 /* multiple channels - create a submenu, with 1 item per channel */
656 Menu* chn_menu = manage (new Menu);
657 MenuList& chn_items (chn_menu->items());
658 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
660 /* add a couple of items to hide/show all of them */
662 chn_items.push_back (
663 MenuElem (_("Hide all channels"),
664 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
665 false, param_without_channel)));
666 chn_items.push_back (
667 MenuElem (_("Show all channels"),
668 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
669 true, param_without_channel)));
671 for (uint8_t chn = 0; chn < 16; chn++) {
672 if (selected_channels & (0x0001 << chn)) {
674 /* for each selected channel, add a menu item for this controller */
676 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
677 chn_items.push_back (
678 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
679 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
680 fully_qualified_param)));
682 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
683 bool visible = false;
686 if (track->marked_for_display()) {
691 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
692 _channel_command_menu_map[fully_qualified_param] = cmi;
693 cmi->set_active (visible);
697 /* now create an item in the parent menu that has the per-channel list as a submenu */
699 items.push_back (MenuElem (label, *chn_menu));
703 /* just one channel - create a single menu item for this command+channel combination*/
705 for (uint8_t chn = 0; chn < 16; chn++) {
706 if (selected_channels & (0x0001 << chn)) {
708 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
710 CheckMenuElem (label,
711 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
712 fully_qualified_param)));
714 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
715 bool visible = false;
718 if (track->marked_for_display()) {
723 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
724 _channel_command_menu_map[fully_qualified_param] = cmi;
725 cmi->set_active (visible);
727 /* one channel only */
734 /** Add a single menu item for a controller on one channel. */
736 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
738 const std::string& name)
740 using namespace Menu_Helpers;
742 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
743 for (uint8_t chn = 0; chn < 16; chn++) {
744 if (selected_channels & (0x0001 << chn)) {
746 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
747 ctl_items.push_back (
749 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
751 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
752 fully_qualified_param)));
753 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
755 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
756 fully_qualified_param);
758 bool visible = false;
760 if (track->marked_for_display()) {
765 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
766 _controller_menu_map[fully_qualified_param] = cmi;
767 cmi->set_active (visible);
769 /* one channel only */
775 /** Add a submenu with 1 item per channel for a controller on many channels. */
777 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
779 const std::string& name)
781 using namespace Menu_Helpers;
783 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
785 Menu* chn_menu = manage (new Menu);
786 MenuList& chn_items (chn_menu->items());
788 /* add a couple of items to hide/show this controller on all channels */
790 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
791 chn_items.push_back (
792 MenuElem (_("Hide all channels"),
793 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
794 false, param_without_channel)));
795 chn_items.push_back (
796 MenuElem (_("Show all channels"),
797 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
798 true, param_without_channel)));
800 for (uint8_t chn = 0; chn < 16; chn++) {
801 if (selected_channels & (0x0001 << chn)) {
803 /* for each selected channel, add a menu item for this controller */
805 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
806 chn_items.push_back (
807 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
808 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
809 fully_qualified_param)));
811 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
812 fully_qualified_param);
813 bool visible = false;
816 if (track->marked_for_display()) {
821 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
822 _controller_menu_map[fully_qualified_param] = cmi;
823 cmi->set_active (visible);
827 /* add the per-channel menu to the list of controllers, with the name of the controller */
828 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
830 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
833 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
834 MidiTimeAxisView::get_device_mode()
836 using namespace MIDI::Name;
838 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
840 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
843 return device_names->custom_device_mode_by_name(
844 gui_property (X_("midnam-custom-device-mode")));
847 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
848 MidiTimeAxisView::get_device_names()
850 using namespace MIDI::Name;
852 const std::string model = gui_property (X_("midnam-model-name"));
854 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
855 .document_by_model(model);
857 return midnam->master_device_names(model);
859 return boost::shared_ptr<MasterDeviceNames>();
864 MidiTimeAxisView::build_controller_menu ()
866 using namespace Menu_Helpers;
868 if (controller_menu) {
869 /* it exists and has not been invalidated by a channel mode change */
873 controller_menu = new Menu; // explicitly managed by us
874 MenuList& items (controller_menu->items());
876 /* create several "top level" menu items for sets of controllers (16 at a
877 time), and populate each one with a submenu for each controller+channel
878 combination covering the currently selected channels for this track
881 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
883 /* count the number of selected channels because we will build a different menu
884 structure if there is more than 1 selected.
888 for (uint8_t chn = 0; chn < 16; chn++) {
889 if (selected_channels & (0x0001 << chn)) {
896 using namespace MIDI::Name;
897 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
899 if (device_names && !device_names->controls().empty()) {
900 /* Controllers names available in midnam file, generate fancy menu */
901 unsigned n_items = 0;
902 unsigned n_groups = 0;
904 /* TODO: This is not correct, should look up the currently applicable ControlNameList
905 and only build a menu for that one. */
906 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
907 l != device_names->controls().end(); ++l) {
908 boost::shared_ptr<ControlNameList> name_list = l->second;
909 Menu* ctl_menu = NULL;
911 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
912 c != name_list->controls().end();) {
913 const uint16_t ctl = c->second->number();
914 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
915 /* Skip bank select controllers since they're handled specially */
917 /* Create a new submenu */
918 ctl_menu = manage (new Menu);
921 MenuList& ctl_items (ctl_menu->items());
923 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
925 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
930 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
931 /* Submenu has 16 items or we're done, add it to controller menu and reset */
933 MenuElem(string_compose(_("Controllers %1-%2"),
934 (16 * n_groups), (16 * n_groups) + n_items - 1),
943 /* No controllers names, generate generic numeric menu */
944 for (int i = 0; i < 127; i += 16) {
945 Menu* ctl_menu = manage (new Menu);
946 MenuList& ctl_items (ctl_menu->items());
948 for (int ctl = i; ctl < i+16; ++ctl) {
949 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
950 /* Skip bank select controllers since they're handled specially */
955 add_multi_channel_controller_item(
956 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
958 add_single_channel_controller_item(
959 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
963 /* Add submenu for this block of controllers to controller menu */
965 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
972 MidiTimeAxisView::build_note_mode_menu()
974 using namespace Menu_Helpers;
976 Menu* mode_menu = manage (new Menu);
977 MenuList& items = mode_menu->items();
978 mode_menu->set_name ("ArdourContextMenu");
980 RadioMenuItem::Group mode_group;
982 RadioMenuElem (mode_group,_("Sustained"),
983 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
985 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
986 _note_mode_item->set_active(_note_mode == Sustained);
989 RadioMenuElem (mode_group, _("Percussive"),
990 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
992 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
993 _percussion_mode_item->set_active(_note_mode == Percussive);
999 MidiTimeAxisView::build_color_mode_menu()
1001 using namespace Menu_Helpers;
1003 Menu* mode_menu = manage (new Menu);
1004 MenuList& items = mode_menu->items();
1005 mode_menu->set_name ("ArdourContextMenu");
1007 RadioMenuItem::Group mode_group;
1009 RadioMenuElem (mode_group, _("Meter Colors"),
1010 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1011 MeterColors, false, true, true)));
1012 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1013 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1016 RadioMenuElem (mode_group, _("Channel Colors"),
1017 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1018 ChannelColors, false, true, true)));
1019 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1020 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1023 RadioMenuElem (mode_group, _("Track Color"),
1024 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1025 TrackColor, false, true, true)));
1026 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1027 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1033 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1035 if (apply_to_selection) {
1036 _editor.get_selection().tracks.foreach_midi_time_axis (
1037 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1039 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1041 midi_track()->set_note_mode(mode);
1042 set_gui_property ("note-mode", enum_2_string(_note_mode));
1043 _view->redisplay_track();
1049 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1051 if (apply_to_selection) {
1052 _editor.get_selection().tracks.foreach_midi_time_axis (
1053 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1055 if (_color_mode == mode && !force) {
1059 if (_channel_selector) {
1060 if (mode == ChannelColors) {
1061 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1063 _channel_selector->set_default_channel_color();
1068 set_gui_property ("color-mode", enum_2_string(_color_mode));
1070 _view->redisplay_track();
1076 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1078 if (apply_to_selection) {
1079 _editor.get_selection().tracks.foreach_midi_time_axis (
1080 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1082 if (!_ignore_signals) {
1083 midi_view()->set_note_range(range);
1089 MidiTimeAxisView::update_range()
1091 MidiGhostRegion* mgr;
1093 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1094 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1095 mgr->update_range();
1101 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1103 using namespace MIDI::Name;
1105 if (apply_to_selection) {
1106 _editor.get_selection().tracks.foreach_midi_time_axis (
1107 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1110 // Show existing automation
1111 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1113 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1114 create_automation_child(*i, true);
1117 // Show automation for all controllers named in midnam file
1118 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1119 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1120 device_names && !device_names->controls().empty()) {
1121 const std::string device_mode = _midnam_custom_device_mode_selector.get_active_text();
1122 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1123 for (uint32_t chn = 0; chn < 16; ++chn) {
1124 if ((selected_channels & (0x0001 << chn)) == 0) {
1125 // Channel not in use
1129 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1135 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1136 chan_names->control_list_name());
1137 if (!control_names) {
1141 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1142 c != control_names->controls().end();
1144 const uint16_t ctl = c->second->number();
1145 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1146 /* Skip bank select controllers since they're handled specially */
1147 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1148 create_automation_child(param, true);
1155 RouteTimeAxisView::show_all_automation ();
1160 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1162 if (apply_to_selection) {
1163 _editor.get_selection().tracks.foreach_midi_time_axis (
1164 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1167 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1169 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1170 create_automation_child (*i, true);
1174 RouteTimeAxisView::show_existing_automation ();
1178 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1181 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1183 if (param.type() == NullAutomation) {
1187 AutomationTracks::iterator existing = _automation_tracks.find (param);
1189 if (existing != _automation_tracks.end()) {
1191 /* automation track created because we had existing data for
1192 * the processor, but visibility may need to be controlled
1193 * since it will have been set visible by default.
1196 existing->second->set_marked_for_display (show);
1205 boost::shared_ptr<AutomationTimeAxisView> track;
1206 boost::shared_ptr<AutomationControl> control;
1209 switch (param.type()) {
1211 case GainAutomation:
1212 create_gain_automation_child (param, show);
1215 case MuteAutomation:
1216 create_mute_automation_child (param, show);
1219 case PluginAutomation:
1220 /* handled elsewhere */
1223 case MidiCCAutomation:
1224 case MidiPgmChangeAutomation:
1225 case MidiPitchBenderAutomation:
1226 case MidiChannelPressureAutomation:
1227 case MidiSystemExclusiveAutomation:
1228 /* These controllers are region "automation" - they are owned
1229 * by regions (and their MidiModels), not by the track. As a
1230 * result there is no AutomationList/Line for the track, but we create
1231 * a controller for the user to write immediate events, so the editor
1232 * can act as a control surface for the present MIDI controllers.
1234 * TODO: Record manipulation of the controller to regions?
1237 control = _route->automation_control(param, true);
1238 track.reset (new AutomationTimeAxisView (
1241 control ? _route : boost::shared_ptr<Automatable> (),
1248 _route->describe_parameter(param)));
1251 _view->foreach_regionview (
1252 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1255 add_automation_child (param, track, show);
1258 case PanWidthAutomation:
1259 case PanElevationAutomation:
1260 case PanAzimuthAutomation:
1261 ensure_pan_views (show);
1265 error << "MidiTimeAxisView: unknown automation child "
1266 << EventTypeMap::instance().to_symbol(param) << endmsg;
1271 MidiTimeAxisView::route_active_changed ()
1273 RouteUI::route_active_changed ();
1276 if (_route->active()) {
1277 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1278 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1279 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1280 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1282 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1283 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1284 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1285 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1288 if (_route->active()) {
1289 controls_ebox.set_name ("BusControlsBaseUnselected");
1290 time_axis_frame.set_name ("BusControlsBaseUnselected");
1291 controls_base_selected_name = "BusControlsBaseSelected";
1292 controls_base_unselected_name = "BusControlsBaseUnselected";
1294 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1295 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1296 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1297 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1303 MidiTimeAxisView::set_note_selection (uint8_t note)
1305 if (!_editor.internal_editing()) {
1309 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1311 if (_view->num_selected_regionviews() == 0) {
1312 _view->foreach_regionview (
1313 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1316 _view->foreach_selected_regionview (
1317 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1323 MidiTimeAxisView::add_note_selection (uint8_t note)
1325 if (!_editor.internal_editing()) {
1329 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1331 if (_view->num_selected_regionviews() == 0) {
1332 _view->foreach_regionview (
1333 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1336 _view->foreach_selected_regionview (
1337 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1343 MidiTimeAxisView::extend_note_selection (uint8_t note)
1345 if (!_editor.internal_editing()) {
1349 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1351 if (_view->num_selected_regionviews() == 0) {
1352 _view->foreach_regionview (
1353 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1356 _view->foreach_selected_regionview (
1357 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1363 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1365 if (!_editor.internal_editing()) {
1369 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1371 if (_view->num_selected_regionviews() == 0) {
1372 _view->foreach_regionview (
1373 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1376 _view->foreach_selected_regionview (
1377 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1383 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1385 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1389 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1391 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1395 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1397 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1401 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1403 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1407 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1409 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1413 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1414 bool changed = false;
1418 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1420 for (uint32_t chn = 0; chn < 16; ++chn) {
1421 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1422 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1428 if ((selected_channels & (0x0001 << chn)) == 0) {
1429 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1430 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1432 changed = track->set_marked_for_display (false) || changed;
1434 changed = track->set_marked_for_display (true) || changed;
1441 /* TODO: Bender, Pressure */
1443 /* invalidate the controller menu, so that we rebuild it next time */
1444 _controller_menu_map.clear ();
1445 delete controller_menu;
1446 controller_menu = 0;
1454 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1456 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1461 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1462 if (i != _controller_menu_map.end()) {
1466 i = _channel_command_menu_map.find (param);
1467 if (i != _channel_command_menu_map.end()) {
1474 boost::shared_ptr<MidiRegion>
1475 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1477 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1479 real_editor->begin_reversible_command (Operations::create_region);
1480 playlist()->clear_changes ();
1482 real_editor->snap_to (pos, RoundNearest);
1484 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1487 plist.add (ARDOUR::Properties::start, 0);
1488 plist.add (ARDOUR::Properties::length, length);
1489 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1491 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1493 playlist()->add_region (region, pos);
1494 _session->add_command (new StatefulDiffCommand (playlist()));
1497 real_editor->commit_reversible_command ();
1500 return boost::dynamic_pointer_cast<MidiRegion>(region);
1504 MidiTimeAxisView::ensure_step_editor ()
1506 if (!_step_editor) {
1507 _step_editor = new StepEditor (_editor, midi_track(), *this);
1512 MidiTimeAxisView::start_step_editing ()
1514 ensure_step_editor ();
1515 _step_editor->start_step_editing ();
1519 MidiTimeAxisView::stop_step_editing ()
1522 _step_editor->stop_step_editing ();
1526 /** @return channel (counted from 0) to add an event to, based on the current setting
1527 * of the channel selector.
1530 MidiTimeAxisView::get_channel_for_add () const
1532 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1534 uint8_t channel = 0;
1536 /* pick the highest selected channel, unless all channels are selected,
1537 which is interpreted to mean channel 1 (zero)
1540 for (uint16_t i = 0; i < 16; ++i) {
1541 if (chn_mask & (1<<i)) {
1547 if (chn_cnt == 16) {
1555 MidiTimeAxisView::note_range_changed ()
1557 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1558 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1562 MidiTimeAxisView::contents_height_changed ()
1564 _range_scroomer->queue_resize ();
1568 MidiTimeAxisView::playback_channel_mode_changed ()
1570 switch (midi_track()->get_playback_channel_mode()) {
1572 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1574 case FilterChannels:
1575 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1578 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1584 MidiTimeAxisView::capture_channel_mode_changed ()
1586 switch (midi_track()->get_capture_channel_mode()) {
1588 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1590 case FilterChannels:
1591 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1594 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));