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;
102 // Minimum height at which a control is displayed
103 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
104 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
106 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
107 : AxisView(sess) // virtually inherited
108 , RouteTimeAxisView(ed, sess, canvas)
109 , _ignore_signals(false)
111 , _piano_roll_header(0)
112 , _note_mode(Sustained)
114 , _percussion_mode_item(0)
115 , _color_mode(MeterColors)
116 , _meter_color_mode_item(0)
117 , _channel_color_mode_item(0)
118 , _track_color_mode_item(0)
119 , _channel_selector (0)
120 , _step_edit_item (0)
121 , controller_menu (0)
127 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
131 _view = new MidiStreamView (*this);
134 _piano_roll_header = new PianoRollHeader(*midi_view());
135 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
136 _range_scroomer->DoubleClicked.connect (
137 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
138 MidiStreamView::ContentsRange, false));
141 /* This next call will result in our height being set up, so it must come after
142 the creation of the piano roll / range scroomer as their visibility is set up
145 RouteTimeAxisView::set_route (rt);
147 _view->apply_color (_color, StreamView::RegionColor);
149 subplugin_menu.set_name ("ArdourContextMenu");
151 if (!gui_property ("note-range-min").empty ()) {
152 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
153 atoi (gui_property ("note-range-max").c_str()),
157 midi_view()->NoteRangeChanged.connect (
158 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
159 _view->ContentsHeightChanged.connect (
160 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
162 ignore_toggle = false;
164 if (is_midi_track()) {
165 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
166 time_axis_frame.set_name ("MidiTimeAxisViewControlsBaseUnselected");
167 _note_mode = midi_track()->note_mode();
168 } else { // MIDI bus (which doesn't exist yet..)
169 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
170 time_axis_frame.set_name ("MidiBusControlsBaseUnselected");
173 /* if set_state above didn't create a gain automation child, we need to make one */
174 if (automation_child (GainAutomation) == 0) {
175 create_automation_child (GainAutomation, false);
178 /* if set_state above didn't create a mute automation child, we need to make one */
179 if (automation_child (MuteAutomation) == 0) {
180 create_automation_child (MuteAutomation, false);
183 if (_route->panner_shell()) {
184 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
187 /* map current state of the route */
188 ensure_pan_views (false);
190 processors_changed (RouteProcessorChange ());
192 _route->processors_changed.connect (*this, invalidator (*this),
193 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
197 _piano_roll_header->SetNoteSelection.connect (
198 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
199 _piano_roll_header->AddNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
201 _piano_roll_header->ExtendNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
203 _piano_roll_header->ToggleNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
206 /* Suspend updates of the StreamView during scroomer drags to speed things up */
207 _range_scroomer->DragStarting.connect (
208 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
209 _range_scroomer->DragFinishing.connect (
210 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
212 /* Put the scroomer and the keyboard in a VBox with a padding
213 label so that they can be reduced in height for stacked-view
217 HSeparator* separator = manage (new HSeparator());
218 separator->set_name("TrackSeparator");
219 separator->set_size_request(-1, 1);
222 VBox* v = manage (new VBox);
223 HBox* h = manage (new HBox);
224 h->pack_end (*_piano_roll_header);
225 h->pack_end (*_range_scroomer);
226 v->pack_start (*separator, false, false);
227 v->pack_start (*h, true, true);
230 top_hbox.remove(scroomer_placeholder);
231 time_axis_hbox.pack_end(*v, false, false, 0);
232 midi_scroomer_size_group->add_widget (*v);
234 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
235 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
236 controls_base_selected_name = "MidiTrackControlsBaseSelected";
237 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
239 midi_view()->NoteRangeChanged.connect (
240 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
242 /* ask for notifications of any new RegionViews */
243 _view->RegionViewAdded.connect (
244 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
246 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
247 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
249 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
250 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
252 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
253 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
255 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
256 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
259 playback_channel_mode_changed ();
260 capture_channel_mode_changed ();
262 if (!_editor.have_idled()) {
263 /* first idle will do what we need */
269 typedef MIDI::Name::MidiPatchManager PatchManager;
271 PatchManager& patch_manager = PatchManager::instance();
273 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
274 m != patch_manager.devices_by_manufacturer().end(); ++m) {
275 Menu* menu = Gtk::manage(new Menu);
276 Menu_Helpers::MenuList& items = menu->items();
278 // Build manufacturer submenu
279 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
280 n != m->second.end(); ++n) {
281 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
283 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
286 items.push_back(elem);
289 // Add manufacturer submenu to selector
290 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
293 if (gui_property (X_("midnam-model-name")).empty()) {
294 set_gui_property (X_("midnam-model-name"), "Generic");
297 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
298 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
300 set_gui_property (X_("midnam-custom-device-mode"),
301 *device_names->custom_device_mode_names().begin());
305 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
306 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
308 _midi_controls_box.set_homogeneous(false);
309 _midi_controls_box.set_border_width (2);
311 _channel_status_box.set_homogeneous (false);
312 _channel_status_box.set_spacing (4);
314 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
315 channel_selector_button->set_name ("route button");
316 ARDOUR_UI::instance()->set_tip (channel_selector_button, _("Click to edit channel settings"));
318 /* fixed sized labels to prevent silly nonsense (though obviously,
319 * they cause their own too)
321 set_size_request_to_display_given_text(_playback_channel_status, "Play: somemo", 2, 2); // TODO use _("Play: all/some")
322 set_size_request_to_display_given_text(_capture_channel_status, "Rec: somemo", 2, 2); // TODO use _("Rec: all/some")
324 _channel_status_box.pack_start (_playback_channel_status, false, false);
325 _channel_status_box.pack_start (_capture_channel_status, false, false);
326 _channel_status_box.pack_end (*channel_selector_button, false, false);
327 _channel_status_box.show_all ();
329 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
331 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
333 if (!patch_manager.all_models().empty()) {
335 _midnam_model_selector.show ();
336 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
338 _midnam_custom_device_mode_selector.show ();
340 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
343 model_changed(gui_property(X_("midnam-model-name")));
344 custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
346 controls_vbox.pack_start(_midi_controls_box, false, false);
348 const string color_mode = gui_property ("color-mode");
349 if (!color_mode.empty()) {
350 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
351 if (_channel_selector && _color_mode == ChannelColors) {
352 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
356 set_color_mode (_color_mode, true, false);
358 const string note_mode = gui_property ("note-mode");
359 if (!note_mode.empty()) {
360 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
361 if (_percussion_mode_item) {
362 _percussion_mode_item->set_active (_note_mode == Percussive);
366 /* Look for any GUI object state nodes that represent automation children
367 * that should exist, and create the children.
370 const list<string> gui_ids = gui_object_state().all_ids ();
371 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
374 Evoral::Parameter parameter (0, 0, 0);
376 bool const p = AutomationTimeAxisView::parse_state_id (
377 *i, route_id, has_parameter, parameter);
378 if (p && route_id == _route->id () && has_parameter) {
379 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
380 create_automation_child (parameter, string_is_affirmative (visible));
386 MidiTimeAxisView::first_idle ()
393 MidiTimeAxisView::~MidiTimeAxisView ()
395 delete _channel_selector;
397 delete _piano_roll_header;
398 _piano_roll_header = 0;
400 delete _range_scroomer;
403 delete controller_menu;
408 MidiTimeAxisView::enter_internal_edit_mode ()
411 midi_view()->enter_internal_edit_mode ();
416 MidiTimeAxisView::leave_internal_edit_mode ()
419 midi_view()->leave_internal_edit_mode ();
424 MidiTimeAxisView::check_step_edit ()
426 ensure_step_editor ();
427 _step_editor->check_step_edit ();
431 MidiTimeAxisView::model_changed(const std::string& model)
433 set_gui_property (X_("midnam-model-name"), model);
435 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
436 .custom_device_mode_names_by_model(model);
438 _midnam_model_selector.set_text(model);
439 _midnam_custom_device_mode_selector.clear_items();
441 for (std::list<std::string>::const_iterator i = device_modes.begin();
442 i != device_modes.end(); ++i) {
443 _midnam_custom_device_mode_selector.AddMenuElem(
444 Gtk::Menu_Helpers::MenuElem(
445 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
449 if (!device_modes.empty()) {
450 custom_device_mode_changed(device_modes.front());
453 if (device_modes.size() > 1) {
454 _midnam_custom_device_mode_selector.show();
456 _midnam_custom_device_mode_selector.hide();
459 _route->instrument_info().set_external_instrument (model, device_modes.front());
461 // Rebuild controller menu
462 _controller_menu_map.clear ();
463 delete controller_menu;
465 build_automation_action_menu(false);
469 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
471 const std::string model = gui_property (X_("midnam-model-name"));
473 set_gui_property (X_("midnam-custom-device-mode"), mode);
474 _midnam_custom_device_mode_selector.set_text(mode);
475 _route->instrument_info().set_external_instrument (model, mode);
479 MidiTimeAxisView::midi_view()
481 return dynamic_cast<MidiStreamView*>(_view);
485 MidiTimeAxisView::set_height (uint32_t h)
487 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
488 _midi_controls_box.show ();
490 _midi_controls_box.hide();
493 if (h >= KEYBOARD_MIN_HEIGHT) {
494 if (is_track() && _range_scroomer) {
495 _range_scroomer->show();
497 if (is_track() && _piano_roll_header) {
498 _piano_roll_header->show();
501 if (is_track() && _range_scroomer) {
502 _range_scroomer->hide();
504 if (is_track() && _piano_roll_header) {
505 _piano_roll_header->hide();
509 /* We need to do this after changing visibility of our stuff, as it will
510 eventually trigger a call to Editor::reset_controls_layout_width(),
511 which needs to know if we have just shown or hidden a scroomer /
514 RouteTimeAxisView::set_height (h);
518 MidiTimeAxisView::append_extra_display_menu_items ()
520 using namespace Menu_Helpers;
522 MenuList& items = display_menu->items();
525 Menu *range_menu = manage(new Menu);
526 MenuList& range_items = range_menu->items();
527 range_menu->set_name ("ArdourContextMenu");
529 range_items.push_back (
530 MenuElem (_("Show Full Range"),
531 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
532 MidiStreamView::FullRange, true)));
534 range_items.push_back (
535 MenuElem (_("Fit Contents"),
536 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
537 MidiStreamView::ContentsRange, true)));
539 items.push_back (MenuElem (_("Note Range"), *range_menu));
540 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
541 items.push_back (MenuElem (_("Channel Selector"),
542 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
544 color_mode_menu = build_color_mode_menu();
545 if (color_mode_menu) {
546 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
549 items.push_back (SeparatorElem ());
553 MidiTimeAxisView::toggle_channel_selector ()
555 if (!_channel_selector) {
556 _channel_selector = new MidiChannelSelectorWindow (midi_track());
558 if (_color_mode == ChannelColors) {
559 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
561 _channel_selector->set_default_channel_color ();
564 _channel_selector->show_all ();
566 _channel_selector->cycle_visibility ();
571 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
573 using namespace Menu_Helpers;
575 /* If we have a controller menu, we need to detach it before
576 RouteTimeAxis::build_automation_action_menu destroys the
577 menu it is attached to. Otherwise GTK destroys
578 controller_menu's gobj, meaning that it can't be reattached
579 below. See bug #3134.
582 if (controller_menu) {
583 detach_menu (*controller_menu);
586 _channel_command_menu_map.clear ();
587 RouteTimeAxisView::build_automation_action_menu (for_selection);
589 MenuList& automation_items = automation_action_menu->items();
591 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
593 if (selected_channels != 0) {
595 automation_items.push_back (SeparatorElem());
597 /* these 2 MIDI "command" types are semantically more like automation
598 than note data, but they are not MIDI controllers. We give them
599 special status in this menu, since they will not show up in the
600 controller list and anyone who actually knows something about MIDI
601 (!) would not expect to find them there.
604 add_channel_command_menu_item (
605 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
606 automation_items.back().set_sensitive (
607 !for_selection || _editor.get_selection().tracks.size() == 1);
608 add_channel_command_menu_item (
609 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
610 automation_items.back().set_sensitive (
611 !for_selection || _editor.get_selection().tracks.size() == 1);
613 /* now all MIDI controllers. Always offer the possibility that we will
614 rebuild the controllers menu since it might need to be updated after
615 a channel mode change or other change. Also detach it first in case
616 it has been used anywhere else.
619 build_controller_menu ();
621 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
622 automation_items.back().set_sensitive (
623 !for_selection || _editor.get_selection().tracks.size() == 1);
625 automation_items.push_back (
626 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
627 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
632 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
634 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
636 for (uint8_t chn = 0; chn < 16; chn++) {
637 if (selected_channels & (0x0001 << chn)) {
639 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
640 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
643 menu->set_active (yn);
650 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
652 AutomationType auto_type,
655 using namespace Menu_Helpers;
657 /* count the number of selected channels because we will build a different menu
658 structure if there is more than 1 selected.
661 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
664 for (uint8_t chn = 0; chn < 16; chn++) {
665 if (selected_channels & (0x0001 << chn)) {
674 /* multiple channels - create a submenu, with 1 item per channel */
676 Menu* chn_menu = manage (new Menu);
677 MenuList& chn_items (chn_menu->items());
678 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
680 /* add a couple of items to hide/show all of them */
682 chn_items.push_back (
683 MenuElem (_("Hide all channels"),
684 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
685 false, param_without_channel)));
686 chn_items.push_back (
687 MenuElem (_("Show all channels"),
688 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
689 true, param_without_channel)));
691 for (uint8_t chn = 0; chn < 16; chn++) {
692 if (selected_channels & (0x0001 << chn)) {
694 /* for each selected channel, add a menu item for this controller */
696 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
697 chn_items.push_back (
698 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
699 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
700 fully_qualified_param)));
702 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
703 bool visible = false;
706 if (track->marked_for_display()) {
711 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
712 _channel_command_menu_map[fully_qualified_param] = cmi;
713 cmi->set_active (visible);
717 /* now create an item in the parent menu that has the per-channel list as a submenu */
719 items.push_back (MenuElem (label, *chn_menu));
723 /* just one channel - create a single menu item for this command+channel combination*/
725 for (uint8_t chn = 0; chn < 16; chn++) {
726 if (selected_channels & (0x0001 << chn)) {
728 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
730 CheckMenuElem (label,
731 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
732 fully_qualified_param)));
734 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
735 bool visible = false;
738 if (track->marked_for_display()) {
743 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
744 _channel_command_menu_map[fully_qualified_param] = cmi;
745 cmi->set_active (visible);
747 /* one channel only */
754 /** Add a single menu item for a controller on one channel. */
756 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
758 const std::string& name)
760 using namespace Menu_Helpers;
762 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
763 for (uint8_t chn = 0; chn < 16; chn++) {
764 if (selected_channels & (0x0001 << chn)) {
766 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
767 ctl_items.push_back (
769 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
771 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
772 fully_qualified_param)));
773 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
775 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
776 fully_qualified_param);
778 bool visible = false;
780 if (track->marked_for_display()) {
785 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
786 _controller_menu_map[fully_qualified_param] = cmi;
787 cmi->set_active (visible);
789 /* one channel only */
795 /** Add a submenu with 1 item per channel for a controller on many channels. */
797 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
799 const std::string& name)
801 using namespace Menu_Helpers;
803 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
805 Menu* chn_menu = manage (new Menu);
806 MenuList& chn_items (chn_menu->items());
808 /* add a couple of items to hide/show this controller on all channels */
810 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
811 chn_items.push_back (
812 MenuElem (_("Hide all channels"),
813 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
814 false, param_without_channel)));
815 chn_items.push_back (
816 MenuElem (_("Show all channels"),
817 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
818 true, param_without_channel)));
820 for (uint8_t chn = 0; chn < 16; chn++) {
821 if (selected_channels & (0x0001 << chn)) {
823 /* for each selected channel, add a menu item for this controller */
825 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
826 chn_items.push_back (
827 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
828 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
829 fully_qualified_param)));
831 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
832 fully_qualified_param);
833 bool visible = false;
836 if (track->marked_for_display()) {
841 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
842 _controller_menu_map[fully_qualified_param] = cmi;
843 cmi->set_active (visible);
847 /* add the per-channel menu to the list of controllers, with the name of the controller */
848 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
850 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
853 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
854 MidiTimeAxisView::get_device_mode()
856 using namespace MIDI::Name;
858 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
860 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
863 return device_names->custom_device_mode_by_name(
864 gui_property (X_("midnam-custom-device-mode")));
867 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
868 MidiTimeAxisView::get_device_names()
870 using namespace MIDI::Name;
872 const std::string model = gui_property (X_("midnam-model-name"));
874 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
875 .document_by_model(model);
877 return midnam->master_device_names(model);
879 return boost::shared_ptr<MasterDeviceNames>();
884 MidiTimeAxisView::build_controller_menu ()
886 using namespace Menu_Helpers;
888 if (controller_menu) {
889 /* it exists and has not been invalidated by a channel mode change */
893 controller_menu = new Menu; // explicitly managed by us
894 MenuList& items (controller_menu->items());
896 /* create several "top level" menu items for sets of controllers (16 at a
897 time), and populate each one with a submenu for each controller+channel
898 combination covering the currently selected channels for this track
901 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
903 /* count the number of selected channels because we will build a different menu
904 structure if there is more than 1 selected.
908 for (uint8_t chn = 0; chn < 16; chn++) {
909 if (selected_channels & (0x0001 << chn)) {
916 using namespace MIDI::Name;
917 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
919 if (device_names && !device_names->controls().empty()) {
920 /* Controllers names available in midnam file, generate fancy menu */
921 unsigned n_items = 0;
922 unsigned n_groups = 0;
924 /* TODO: This is not correct, should look up the currently applicable ControlNameList
925 and only build a menu for that one. */
926 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
927 l != device_names->controls().end(); ++l) {
928 boost::shared_ptr<ControlNameList> name_list = l->second;
929 Menu* ctl_menu = NULL;
931 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
932 c != name_list->controls().end();) {
933 const uint16_t ctl = c->second->number();
934 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
935 /* Skip bank select controllers since they're handled specially */
937 /* Create a new submenu */
938 ctl_menu = manage (new Menu);
941 MenuList& ctl_items (ctl_menu->items());
943 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
945 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
950 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
951 /* Submenu has 16 items or we're done, add it to controller menu and reset */
953 MenuElem(string_compose(_("Controllers %1-%2"),
954 (16 * n_groups), (16 * n_groups) + n_items - 1),
963 /* No controllers names, generate generic numeric menu */
964 for (int i = 0; i < 127; i += 16) {
965 Menu* ctl_menu = manage (new Menu);
966 MenuList& ctl_items (ctl_menu->items());
968 for (int ctl = i; ctl < i+16; ++ctl) {
969 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
970 /* Skip bank select controllers since they're handled specially */
975 add_multi_channel_controller_item(
976 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
978 add_single_channel_controller_item(
979 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
983 /* Add submenu for this block of controllers to controller menu */
985 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
992 MidiTimeAxisView::build_note_mode_menu()
994 using namespace Menu_Helpers;
996 Menu* mode_menu = manage (new Menu);
997 MenuList& items = mode_menu->items();
998 mode_menu->set_name ("ArdourContextMenu");
1000 RadioMenuItem::Group mode_group;
1002 RadioMenuElem (mode_group,_("Sustained"),
1003 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1005 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1006 _note_mode_item->set_active(_note_mode == Sustained);
1009 RadioMenuElem (mode_group, _("Percussive"),
1010 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1011 Percussive, true)));
1012 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1013 _percussion_mode_item->set_active(_note_mode == Percussive);
1019 MidiTimeAxisView::build_color_mode_menu()
1021 using namespace Menu_Helpers;
1023 Menu* mode_menu = manage (new Menu);
1024 MenuList& items = mode_menu->items();
1025 mode_menu->set_name ("ArdourContextMenu");
1027 RadioMenuItem::Group mode_group;
1029 RadioMenuElem (mode_group, _("Meter Colors"),
1030 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1031 MeterColors, false, true, true)));
1032 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1033 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1036 RadioMenuElem (mode_group, _("Channel Colors"),
1037 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1038 ChannelColors, false, true, true)));
1039 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1040 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1043 RadioMenuElem (mode_group, _("Track Color"),
1044 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1045 TrackColor, false, true, true)));
1046 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1047 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1053 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1055 if (apply_to_selection) {
1056 _editor.get_selection().tracks.foreach_midi_time_axis (
1057 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1059 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1061 midi_track()->set_note_mode(mode);
1062 set_gui_property ("note-mode", enum_2_string(_note_mode));
1063 _view->redisplay_track();
1069 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1071 if (apply_to_selection) {
1072 _editor.get_selection().tracks.foreach_midi_time_axis (
1073 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1075 if (_color_mode == mode && !force) {
1079 if (_channel_selector) {
1080 if (mode == ChannelColors) {
1081 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1083 _channel_selector->set_default_channel_color();
1088 set_gui_property ("color-mode", enum_2_string(_color_mode));
1090 _view->redisplay_track();
1096 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1098 if (apply_to_selection) {
1099 _editor.get_selection().tracks.foreach_midi_time_axis (
1100 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1102 if (!_ignore_signals) {
1103 midi_view()->set_note_range(range);
1109 MidiTimeAxisView::update_range()
1111 MidiGhostRegion* mgr;
1113 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1114 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1115 mgr->update_range();
1121 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1123 using namespace MIDI::Name;
1125 if (apply_to_selection) {
1126 _editor.get_selection().tracks.foreach_midi_time_axis (
1127 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1130 // Show existing automation
1131 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1133 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1134 create_automation_child(*i, true);
1137 // Show automation for all controllers named in midnam file
1138 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1139 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1140 device_names && !device_names->controls().empty()) {
1141 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1142 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1143 for (uint32_t chn = 0; chn < 16; ++chn) {
1144 if ((selected_channels & (0x0001 << chn)) == 0) {
1145 // Channel not in use
1149 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1155 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1156 chan_names->control_list_name());
1157 if (!control_names) {
1161 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1162 c != control_names->controls().end();
1164 const uint16_t ctl = c->second->number();
1165 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1166 /* Skip bank select controllers since they're handled specially */
1167 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1168 create_automation_child(param, true);
1175 RouteTimeAxisView::show_all_automation ();
1180 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1182 if (apply_to_selection) {
1183 _editor.get_selection().tracks.foreach_midi_time_axis (
1184 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1187 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1189 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1190 create_automation_child (*i, true);
1194 RouteTimeAxisView::show_existing_automation ();
1198 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1201 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1203 if (param.type() == NullAutomation) {
1207 AutomationTracks::iterator existing = _automation_tracks.find (param);
1209 if (existing != _automation_tracks.end()) {
1211 /* automation track created because we had existing data for
1212 * the processor, but visibility may need to be controlled
1213 * since it will have been set visible by default.
1216 existing->second->set_marked_for_display (show);
1225 boost::shared_ptr<AutomationTimeAxisView> track;
1226 boost::shared_ptr<AutomationControl> control;
1229 switch (param.type()) {
1231 case GainAutomation:
1232 create_gain_automation_child (param, show);
1235 case MuteAutomation:
1236 create_mute_automation_child (param, show);
1239 case PluginAutomation:
1240 /* handled elsewhere */
1243 case MidiCCAutomation:
1244 case MidiPgmChangeAutomation:
1245 case MidiPitchBenderAutomation:
1246 case MidiChannelPressureAutomation:
1247 case MidiSystemExclusiveAutomation:
1248 /* These controllers are region "automation" - they are owned
1249 * by regions (and their MidiModels), not by the track. As a
1250 * result there is no AutomationList/Line for the track, but we create
1251 * a controller for the user to write immediate events, so the editor
1252 * can act as a control surface for the present MIDI controllers.
1254 * TODO: Record manipulation of the controller to regions?
1257 control = _route->automation_control(param, true);
1258 track.reset (new AutomationTimeAxisView (
1261 control ? _route : boost::shared_ptr<Automatable> (),
1268 _route->describe_parameter(param)));
1271 _view->foreach_regionview (
1272 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1275 add_automation_child (param, track, show);
1278 case PanWidthAutomation:
1279 case PanElevationAutomation:
1280 case PanAzimuthAutomation:
1281 ensure_pan_views (show);
1285 error << "MidiTimeAxisView: unknown automation child "
1286 << EventTypeMap::instance().to_symbol(param) << endmsg;
1291 MidiTimeAxisView::route_active_changed ()
1293 RouteUI::route_active_changed ();
1296 if (_route->active()) {
1297 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1298 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1299 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1300 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1302 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1303 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1304 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1305 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1308 if (_route->active()) {
1309 controls_ebox.set_name ("BusControlsBaseUnselected");
1310 time_axis_frame.set_name ("BusControlsBaseUnselected");
1311 controls_base_selected_name = "BusControlsBaseSelected";
1312 controls_base_unselected_name = "BusControlsBaseUnselected";
1314 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1315 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1316 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1317 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1323 MidiTimeAxisView::set_note_selection (uint8_t note)
1325 if (!_editor.internal_editing()) {
1329 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::set_note_selection_region_view),
1336 _view->foreach_selected_regionview (
1337 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1343 MidiTimeAxisView::add_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::add_note_selection_region_view),
1356 _view->foreach_selected_regionview (
1357 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1363 MidiTimeAxisView::extend_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::extend_note_selection_region_view),
1376 _view->foreach_selected_regionview (
1377 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1383 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1385 if (!_editor.internal_editing()) {
1389 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1391 if (_view->num_selected_regionviews() == 0) {
1392 _view->foreach_regionview (
1393 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1396 _view->foreach_selected_regionview (
1397 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1403 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1405 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1409 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1411 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1415 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1417 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1421 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1423 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1427 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1429 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1433 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1434 bool changed = false;
1438 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1440 for (uint32_t chn = 0; chn < 16; ++chn) {
1441 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1442 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1448 if ((selected_channels & (0x0001 << chn)) == 0) {
1449 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1450 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1452 changed = track->set_marked_for_display (false) || changed;
1454 changed = track->set_marked_for_display (true) || changed;
1461 /* TODO: Bender, Pressure */
1463 /* invalidate the controller menu, so that we rebuild it next time */
1464 _controller_menu_map.clear ();
1465 delete controller_menu;
1466 controller_menu = 0;
1474 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1476 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1481 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1482 if (i != _controller_menu_map.end()) {
1486 i = _channel_command_menu_map.find (param);
1487 if (i != _channel_command_menu_map.end()) {
1494 boost::shared_ptr<MidiRegion>
1495 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1497 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1499 real_editor->begin_reversible_command (Operations::create_region);
1500 playlist()->clear_changes ();
1502 real_editor->snap_to (pos, RoundNearest);
1504 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1507 plist.add (ARDOUR::Properties::start, 0);
1508 plist.add (ARDOUR::Properties::length, length);
1509 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1511 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1513 playlist()->add_region (region, pos);
1514 _session->add_command (new StatefulDiffCommand (playlist()));
1517 real_editor->commit_reversible_command ();
1520 return boost::dynamic_pointer_cast<MidiRegion>(region);
1524 MidiTimeAxisView::ensure_step_editor ()
1526 if (!_step_editor) {
1527 _step_editor = new StepEditor (_editor, midi_track(), *this);
1532 MidiTimeAxisView::start_step_editing ()
1534 ensure_step_editor ();
1535 _step_editor->start_step_editing ();
1539 MidiTimeAxisView::stop_step_editing ()
1542 _step_editor->stop_step_editing ();
1546 /** @return channel (counted from 0) to add an event to, based on the current setting
1547 * of the channel selector.
1550 MidiTimeAxisView::get_channel_for_add () const
1552 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1554 uint8_t channel = 0;
1556 /* pick the highest selected channel, unless all channels are selected,
1557 which is interpreted to mean channel 1 (zero)
1560 for (uint16_t i = 0; i < 16; ++i) {
1561 if (chn_mask & (1<<i)) {
1567 if (chn_cnt == 16) {
1575 MidiTimeAxisView::note_range_changed ()
1577 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1578 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1582 MidiTimeAxisView::contents_height_changed ()
1584 _range_scroomer->queue_resize ();
1588 MidiTimeAxisView::playback_channel_mode_changed ()
1590 switch (midi_track()->get_playback_channel_mode()) {
1592 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1594 case FilterChannels:
1595 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1598 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1604 MidiTimeAxisView::capture_channel_mode_changed ()
1606 switch (midi_track()->get_capture_channel_mode()) {
1608 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1610 case FilterChannels:
1611 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1614 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));