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 (10);
296 _channel_status_box.set_homogeneous (false);
297 _channel_status_box.set_spacing (6);
299 _channel_selector_button.set_label (_("Chns"));
300 ARDOUR_UI::instance()->set_tip (_channel_selector_button, _("Click to edit channel settings"));
302 /* fixed sized labels to prevent silly nonsense (though obviously,
303 * they cause their own too)
306 _playback_channel_status.set_size_request (65, -1);
307 _capture_channel_status.set_size_request (60, -1);
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_start (_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.set_size_request(22, 30);
321 _midnam_model_selector.set_border_width(2);
322 _midnam_model_selector.show ();
323 _midi_controls_box.pack_start (_midnam_model_selector);
325 _midnam_custom_device_mode_selector.set_size_request(10, 30);
326 _midnam_custom_device_mode_selector.set_border_width(2);
327 _midnam_custom_device_mode_selector.show ();
329 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
333 custom_device_mode_changed();
335 _midnam_model_selector.signal_changed().connect(
336 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
337 _midnam_custom_device_mode_selector.signal_changed().connect(
338 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
340 controls_vbox.pack_start(_midi_controls_box, false, false);
342 const string color_mode = gui_property ("color-mode");
343 if (!color_mode.empty()) {
344 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
345 if (_channel_selector && _color_mode == ChannelColors) {
346 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
350 set_color_mode (_color_mode, true, false);
352 const string note_mode = gui_property ("note-mode");
353 if (!note_mode.empty()) {
354 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
355 if (_percussion_mode_item) {
356 _percussion_mode_item->set_active (_note_mode == Percussive);
360 /* Look for any GUI object state nodes that represent automation children
361 * that should exist, and create the children.
364 const list<string> gui_ids = gui_object_state().all_ids ();
365 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
368 Evoral::Parameter parameter (0, 0, 0);
370 bool const p = AutomationTimeAxisView::parse_state_id (
371 *i, route_id, has_parameter, parameter);
372 if (p && route_id == _route->id () && has_parameter) {
373 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
374 create_automation_child (parameter, string_is_affirmative (visible));
380 MidiTimeAxisView::first_idle ()
387 MidiTimeAxisView::~MidiTimeAxisView ()
389 delete _channel_selector;
391 delete _piano_roll_header;
392 _piano_roll_header = 0;
394 delete _range_scroomer;
397 delete controller_menu;
402 MidiTimeAxisView::enter_internal_edit_mode ()
405 midi_view()->enter_internal_edit_mode ();
410 MidiTimeAxisView::leave_internal_edit_mode ()
413 midi_view()->leave_internal_edit_mode ();
418 MidiTimeAxisView::check_step_edit ()
420 ensure_step_editor ();
421 _step_editor->check_step_edit ();
425 MidiTimeAxisView::model_changed()
427 const Glib::ustring model = _midnam_model_selector.get_active_text();
428 set_gui_property (X_("midnam-model-name"), model);
430 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
431 .custom_device_mode_names_by_model(model);
433 _midnam_custom_device_mode_selector.clear_items();
435 for (std::list<std::string>::const_iterator i = device_modes.begin();
436 i != device_modes.end(); ++i) {
437 _midnam_custom_device_mode_selector.append_text(*i);
440 _midnam_custom_device_mode_selector.set_active(0);
442 _route->instrument_info().set_external_instrument (
443 _midnam_model_selector.get_active_text(),
444 _midnam_custom_device_mode_selector.get_active_text());
446 // Rebuild controller menu
447 _controller_menu_map.clear ();
448 delete controller_menu;
450 build_automation_action_menu(false);
454 MidiTimeAxisView::custom_device_mode_changed()
456 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
457 set_gui_property (X_("midnam-custom-device-mode"), mode);
458 _route->instrument_info().set_external_instrument (
459 _midnam_model_selector.get_active_text(), mode);
463 MidiTimeAxisView::midi_view()
465 return dynamic_cast<MidiStreamView*>(_view);
469 MidiTimeAxisView::set_height (uint32_t h)
471 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
472 _midi_controls_box.show ();
474 _midi_controls_box.hide();
477 if (h >= KEYBOARD_MIN_HEIGHT) {
478 if (is_track() && _range_scroomer) {
479 _range_scroomer->show();
481 if (is_track() && _piano_roll_header) {
482 _piano_roll_header->show();
485 if (is_track() && _range_scroomer) {
486 _range_scroomer->hide();
488 if (is_track() && _piano_roll_header) {
489 _piano_roll_header->hide();
493 /* We need to do this after changing visibility of our stuff, as it will
494 eventually trigger a call to Editor::reset_controls_layout_width(),
495 which needs to know if we have just shown or hidden a scroomer /
498 RouteTimeAxisView::set_height (h);
502 MidiTimeAxisView::append_extra_display_menu_items ()
504 using namespace Menu_Helpers;
506 MenuList& items = display_menu->items();
509 Menu *range_menu = manage(new Menu);
510 MenuList& range_items = range_menu->items();
511 range_menu->set_name ("ArdourContextMenu");
513 range_items.push_back (
514 MenuElem (_("Show Full Range"),
515 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
516 MidiStreamView::FullRange, true)));
518 range_items.push_back (
519 MenuElem (_("Fit Contents"),
520 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
521 MidiStreamView::ContentsRange, true)));
523 items.push_back (MenuElem (_("Note Range"), *range_menu));
524 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
525 items.push_back (MenuElem (_("Channel Selector"),
526 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
528 color_mode_menu = build_color_mode_menu();
529 if (color_mode_menu) {
530 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
533 items.push_back (SeparatorElem ());
537 MidiTimeAxisView::toggle_channel_selector ()
539 if (!_channel_selector) {
540 _channel_selector = new MidiChannelSelectorWindow (midi_track());
542 if (_color_mode == ChannelColors) {
543 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
545 _channel_selector->set_default_channel_color ();
548 _channel_selector->show_all ();
550 _channel_selector->cycle_visibility ();
555 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
557 using namespace Menu_Helpers;
559 /* If we have a controller menu, we need to detach it before
560 RouteTimeAxis::build_automation_action_menu destroys the
561 menu it is attached to. Otherwise GTK destroys
562 controller_menu's gobj, meaning that it can't be reattached
563 below. See bug #3134.
566 if (controller_menu) {
567 detach_menu (*controller_menu);
570 _channel_command_menu_map.clear ();
571 RouteTimeAxisView::build_automation_action_menu (for_selection);
573 MenuList& automation_items = automation_action_menu->items();
575 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
577 if (selected_channels != 0) {
579 automation_items.push_back (SeparatorElem());
581 /* these 2 MIDI "command" types are semantically more like automation
582 than note data, but they are not MIDI controllers. We give them
583 special status in this menu, since they will not show up in the
584 controller list and anyone who actually knows something about MIDI
585 (!) would not expect to find them there.
588 add_channel_command_menu_item (
589 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
590 automation_items.back().set_sensitive (
591 !for_selection || _editor.get_selection().tracks.size() == 1);
592 add_channel_command_menu_item (
593 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
594 automation_items.back().set_sensitive (
595 !for_selection || _editor.get_selection().tracks.size() == 1);
597 /* now all MIDI controllers. Always offer the possibility that we will
598 rebuild the controllers menu since it might need to be updated after
599 a channel mode change or other change. Also detach it first in case
600 it has been used anywhere else.
603 build_controller_menu ();
605 automation_items.push_back (SeparatorElem());
606 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
607 automation_items.back().set_sensitive (
608 !for_selection || _editor.get_selection().tracks.size() == 1);
610 automation_items.push_back (
611 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
612 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
615 automation_items.push_back (SeparatorElem());
616 automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility)));
617 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
618 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
619 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
621 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
623 if (!pan_tracks.empty()) {
624 automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility)));
625 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
626 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
627 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
629 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
630 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
631 _main_automation_menu_map[*p] = pan_automation_item;
638 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
640 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
642 for (uint8_t chn = 0; chn < 16; chn++) {
643 if (selected_channels & (0x0001 << chn)) {
645 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
646 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
649 menu->set_active (yn);
656 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
658 AutomationType auto_type,
661 using namespace Menu_Helpers;
663 /* count the number of selected channels because we will build a different menu
664 structure if there is more than 1 selected.
667 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
670 for (uint8_t chn = 0; chn < 16; chn++) {
671 if (selected_channels & (0x0001 << chn)) {
680 /* multiple channels - create a submenu, with 1 item per channel */
682 Menu* chn_menu = manage (new Menu);
683 MenuList& chn_items (chn_menu->items());
684 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
686 /* add a couple of items to hide/show all of them */
688 chn_items.push_back (
689 MenuElem (_("Hide all channels"),
690 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
691 false, param_without_channel)));
692 chn_items.push_back (
693 MenuElem (_("Show all channels"),
694 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
695 true, param_without_channel)));
697 for (uint8_t chn = 0; chn < 16; chn++) {
698 if (selected_channels & (0x0001 << chn)) {
700 /* for each selected channel, add a menu item for this controller */
702 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
703 chn_items.push_back (
704 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
705 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
706 fully_qualified_param)));
708 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
709 bool visible = false;
712 if (track->marked_for_display()) {
717 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
718 _channel_command_menu_map[fully_qualified_param] = cmi;
719 cmi->set_active (visible);
723 /* now create an item in the parent menu that has the per-channel list as a submenu */
725 items.push_back (MenuElem (label, *chn_menu));
729 /* just one channel - create a single menu item for this command+channel combination*/
731 for (uint8_t chn = 0; chn < 16; chn++) {
732 if (selected_channels & (0x0001 << chn)) {
734 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
736 CheckMenuElem (label,
737 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
738 fully_qualified_param)));
740 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
741 bool visible = false;
744 if (track->marked_for_display()) {
749 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
750 _channel_command_menu_map[fully_qualified_param] = cmi;
751 cmi->set_active (visible);
753 /* one channel only */
760 /** Add a single menu item for a controller on one channel. */
762 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
764 const std::string& name)
766 using namespace Menu_Helpers;
768 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
769 for (uint8_t chn = 0; chn < 16; chn++) {
770 if (selected_channels & (0x0001 << chn)) {
772 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
773 ctl_items.push_back (
775 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
777 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
778 fully_qualified_param)));
779 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
781 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
782 fully_qualified_param);
784 bool visible = false;
786 if (track->marked_for_display()) {
791 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
792 _controller_menu_map[fully_qualified_param] = cmi;
793 cmi->set_active (visible);
795 /* one channel only */
801 /** Add a submenu with 1 item per channel for a controller on many channels. */
803 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
805 const std::string& name)
807 using namespace Menu_Helpers;
809 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
811 Menu* chn_menu = manage (new Menu);
812 MenuList& chn_items (chn_menu->items());
814 /* add a couple of items to hide/show this controller on all channels */
816 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
817 chn_items.push_back (
818 MenuElem (_("Hide all channels"),
819 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
820 false, param_without_channel)));
821 chn_items.push_back (
822 MenuElem (_("Show all channels"),
823 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
824 true, param_without_channel)));
826 for (uint8_t chn = 0; chn < 16; chn++) {
827 if (selected_channels & (0x0001 << chn)) {
829 /* for each selected channel, add a menu item for this controller */
831 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
832 chn_items.push_back (
833 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
834 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
835 fully_qualified_param)));
837 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
838 fully_qualified_param);
839 bool visible = false;
842 if (track->marked_for_display()) {
847 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
848 _controller_menu_map[fully_qualified_param] = cmi;
849 cmi->set_active (visible);
853 /* add the per-channel menu to the list of controllers, with the name of the controller */
854 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
856 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
859 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
860 MidiTimeAxisView::get_device_mode()
862 using namespace MIDI::Name;
864 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
866 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
869 return device_names->custom_device_mode_by_name(
870 gui_property (X_("midnam-custom-device-mode")));
873 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
874 MidiTimeAxisView::get_device_names()
876 using namespace MIDI::Name;
878 const std::string model = gui_property (X_("midnam-model-name"));
880 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
881 .document_by_model(model);
883 return midnam->master_device_names(model);
885 return boost::shared_ptr<MasterDeviceNames>();
890 MidiTimeAxisView::build_controller_menu ()
892 using namespace Menu_Helpers;
894 if (controller_menu) {
895 /* it exists and has not been invalidated by a channel mode change */
899 controller_menu = new Menu; // explicitly managed by us
900 MenuList& items (controller_menu->items());
902 /* create several "top level" menu items for sets of controllers (16 at a
903 time), and populate each one with a submenu for each controller+channel
904 combination covering the currently selected channels for this track
907 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
909 /* count the number of selected channels because we will build a different menu
910 structure if there is more than 1 selected.
914 for (uint8_t chn = 0; chn < 16; chn++) {
915 if (selected_channels & (0x0001 << chn)) {
922 using namespace MIDI::Name;
923 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
925 if (device_names && !device_names->controls().empty()) {
926 /* Controllers names available in midnam file, generate fancy menu */
927 unsigned n_items = 0;
928 unsigned n_groups = 0;
930 /* TODO: This is not correct, should look up the currently applicable ControlNameList
931 and only build a menu for that one. */
932 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
933 l != device_names->controls().end(); ++l) {
934 boost::shared_ptr<ControlNameList> name_list = l->second;
935 Menu* ctl_menu = NULL;
937 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
938 c != name_list->controls().end();) {
939 const uint16_t ctl = c->second->number();
940 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
941 /* Skip bank select controllers since they're handled specially */
943 /* Create a new submenu */
944 ctl_menu = manage (new Menu);
947 MenuList& ctl_items (ctl_menu->items());
949 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
951 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
956 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
957 /* Submenu has 16 items or we're done, add it to controller menu and reset */
959 MenuElem(string_compose(_("Controllers %1-%2"),
960 (16 * n_groups), (16 * n_groups) + n_items - 1),
969 /* No controllers names, generate generic numeric menu */
970 for (int i = 0; i < 127; i += 16) {
971 Menu* ctl_menu = manage (new Menu);
972 MenuList& ctl_items (ctl_menu->items());
974 for (int ctl = i; ctl < i+16; ++ctl) {
975 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
976 /* Skip bank select controllers since they're handled specially */
981 add_multi_channel_controller_item(
982 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
984 add_single_channel_controller_item(
985 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
989 /* Add submenu for this block of controllers to controller menu */
991 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
998 MidiTimeAxisView::build_note_mode_menu()
1000 using namespace Menu_Helpers;
1002 Menu* mode_menu = manage (new Menu);
1003 MenuList& items = mode_menu->items();
1004 mode_menu->set_name ("ArdourContextMenu");
1006 RadioMenuItem::Group mode_group;
1008 RadioMenuElem (mode_group,_("Sustained"),
1009 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1011 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1012 _note_mode_item->set_active(_note_mode == Sustained);
1015 RadioMenuElem (mode_group, _("Percussive"),
1016 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1017 Percussive, true)));
1018 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1019 _percussion_mode_item->set_active(_note_mode == Percussive);
1025 MidiTimeAxisView::build_color_mode_menu()
1027 using namespace Menu_Helpers;
1029 Menu* mode_menu = manage (new Menu);
1030 MenuList& items = mode_menu->items();
1031 mode_menu->set_name ("ArdourContextMenu");
1033 RadioMenuItem::Group mode_group;
1035 RadioMenuElem (mode_group, _("Meter Colors"),
1036 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1037 MeterColors, false, true, true)));
1038 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1039 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1042 RadioMenuElem (mode_group, _("Channel Colors"),
1043 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1044 ChannelColors, false, true, true)));
1045 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1046 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1049 RadioMenuElem (mode_group, _("Track Color"),
1050 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1051 TrackColor, false, true, true)));
1052 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1053 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1059 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1061 if (apply_to_selection) {
1062 _editor.get_selection().tracks.foreach_midi_time_axis (
1063 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1065 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1067 midi_track()->set_note_mode(mode);
1068 set_gui_property ("note-mode", enum_2_string(_note_mode));
1069 _view->redisplay_track();
1075 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1077 if (apply_to_selection) {
1078 _editor.get_selection().tracks.foreach_midi_time_axis (
1079 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1081 if (_color_mode == mode && !force) {
1085 if (_channel_selector) {
1086 if (mode == ChannelColors) {
1087 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1089 _channel_selector->set_default_channel_color();
1094 set_gui_property ("color-mode", enum_2_string(_color_mode));
1096 _view->redisplay_track();
1102 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1104 if (apply_to_selection) {
1105 _editor.get_selection().tracks.foreach_midi_time_axis (
1106 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1108 if (!_ignore_signals) {
1109 midi_view()->set_note_range(range);
1115 MidiTimeAxisView::update_range()
1117 MidiGhostRegion* mgr;
1119 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1120 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1121 mgr->update_range();
1127 MidiTimeAxisView::ensure_pan_views (bool show)
1129 bool changed = false;
1130 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1132 (*i)->set_marked_for_display (false);
1135 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1139 if (!_route->panner()) {
1143 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1144 set<Evoral::Parameter>::iterator p;
1146 for (p = params.begin(); p != params.end(); ++p) {
1147 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1149 if (pan_control->parameter().type() == NullAutomation) {
1150 error << "Pan control has NULL automation type!" << endmsg;
1154 if (automation_child (pan_control->parameter ()).get () == 0) {
1156 /* we don't already have an AutomationTimeAxisView for this parameter */
1158 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1160 boost::shared_ptr<AutomationTimeAxisView> t (
1161 new AutomationTimeAxisView (_session,
1165 pan_control->parameter (),
1173 pan_tracks.push_back (t);
1174 add_automation_child (*p, t, show);
1176 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1182 MidiTimeAxisView::update_gain_track_visibility ()
1184 bool const showit = gain_automation_item->get_active();
1186 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1187 gain_track->set_marked_for_display (showit);
1189 /* now trigger a redisplay */
1192 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1198 MidiTimeAxisView::update_pan_track_visibility ()
1200 bool const showit = pan_automation_item->get_active();
1201 bool changed = false;
1203 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1204 if ((*i)->set_marked_for_display (showit)) {
1210 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1215 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1217 using namespace MIDI::Name;
1219 if (apply_to_selection) {
1220 _editor.get_selection().tracks.foreach_midi_time_axis (
1221 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1224 // Show existing automation
1225 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1227 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1228 create_automation_child(*i, true);
1231 // Show automation for all controllers named in midnam file
1232 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1233 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1234 device_names && !device_names->controls().empty()) {
1235 const std::string device_mode = _midnam_custom_device_mode_selector.get_active_text();
1236 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1237 for (uint32_t chn = 0; chn < 16; ++chn) {
1238 if ((selected_channels & (0x0001 << chn)) == 0) {
1239 // Channel not in use
1243 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1249 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1250 chan_names->control_list_name());
1251 if (!control_names) {
1255 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1256 c != control_names->controls().end();
1258 const uint16_t ctl = c->second->number();
1259 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1260 /* Skip bank select controllers since they're handled specially */
1261 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1262 create_automation_child(param, true);
1269 RouteTimeAxisView::show_all_automation ();
1274 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1276 if (apply_to_selection) {
1277 _editor.get_selection().tracks.foreach_midi_time_axis (
1278 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1281 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1283 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1284 create_automation_child (*i, true);
1288 RouteTimeAxisView::show_existing_automation ();
1292 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1295 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1297 if (param.type() == NullAutomation) {
1301 AutomationTracks::iterator existing = _automation_tracks.find (param);
1303 if (existing != _automation_tracks.end()) {
1305 /* automation track created because we had existing data for
1306 * the processor, but visibility may need to be controlled
1307 * since it will have been set visible by default.
1310 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1317 boost::shared_ptr<AutomationTimeAxisView> track;
1318 boost::shared_ptr<AutomationControl> control;
1321 switch (param.type()) {
1323 case GainAutomation:
1324 create_gain_automation_child (param, show);
1327 case MuteAutomation:
1328 create_mute_automation_child (param, show);
1331 case PluginAutomation:
1332 /* handled elsewhere */
1335 case MidiCCAutomation:
1336 case MidiPgmChangeAutomation:
1337 case MidiPitchBenderAutomation:
1338 case MidiChannelPressureAutomation:
1339 case MidiSystemExclusiveAutomation:
1340 /* These controllers are region "automation" - they are owned
1341 * by regions (and their MidiModels), not by the track. As a
1342 * result there is no AutomationList/Line for the track, but we create
1343 * a controller for the user to write immediate events, so the editor
1344 * can act as a control surface for the present MIDI controllers.
1346 * TODO: Record manipulation of the controller to regions?
1349 control = _route->automation_control(param, true);
1350 track.reset (new AutomationTimeAxisView (
1353 control ? _route : boost::shared_ptr<Automatable> (),
1360 _route->describe_parameter(param)));
1363 _view->foreach_regionview (
1364 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1367 add_automation_child (param, track, show);
1370 case PanWidthAutomation:
1371 case PanElevationAutomation:
1372 case PanAzimuthAutomation:
1373 ensure_pan_views (show);
1377 error << "MidiTimeAxisView: unknown automation child "
1378 << EventTypeMap::instance().to_symbol(param) << endmsg;
1383 MidiTimeAxisView::route_active_changed ()
1385 RouteUI::route_active_changed ();
1388 if (_route->active()) {
1389 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1390 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1391 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1392 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1394 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1395 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1396 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1397 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1400 if (_route->active()) {
1401 controls_ebox.set_name ("BusControlsBaseUnselected");
1402 time_axis_frame.set_name ("BusControlsBaseUnselected");
1403 controls_base_selected_name = "BusControlsBaseSelected";
1404 controls_base_unselected_name = "BusControlsBaseUnselected";
1406 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1407 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1408 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1409 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1415 MidiTimeAxisView::set_note_selection (uint8_t note)
1417 if (!_editor.internal_editing()) {
1421 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1423 if (_view->num_selected_regionviews() == 0) {
1424 _view->foreach_regionview (
1425 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1428 _view->foreach_selected_regionview (
1429 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1435 MidiTimeAxisView::add_note_selection (uint8_t note)
1437 if (!_editor.internal_editing()) {
1441 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1443 if (_view->num_selected_regionviews() == 0) {
1444 _view->foreach_regionview (
1445 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1448 _view->foreach_selected_regionview (
1449 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1455 MidiTimeAxisView::extend_note_selection (uint8_t note)
1457 if (!_editor.internal_editing()) {
1461 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1463 if (_view->num_selected_regionviews() == 0) {
1464 _view->foreach_regionview (
1465 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1468 _view->foreach_selected_regionview (
1469 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1475 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1477 if (!_editor.internal_editing()) {
1481 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1483 if (_view->num_selected_regionviews() == 0) {
1484 _view->foreach_regionview (
1485 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1488 _view->foreach_selected_regionview (
1489 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1495 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1497 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1501 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1503 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1507 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1509 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1513 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1515 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1519 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1521 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1525 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1526 bool changed = false;
1530 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1532 for (uint32_t chn = 0; chn < 16; ++chn) {
1533 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1534 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1540 if ((selected_channels & (0x0001 << chn)) == 0) {
1541 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1542 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1544 changed = track->set_marked_for_display (false) || changed;
1546 changed = track->set_marked_for_display (true) || changed;
1553 /* TODO: Bender, Pressure */
1555 /* invalidate the controller menu, so that we rebuild it next time */
1556 _controller_menu_map.clear ();
1557 delete controller_menu;
1558 controller_menu = 0;
1566 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1568 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1573 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1574 if (i != _controller_menu_map.end()) {
1578 i = _channel_command_menu_map.find (param);
1579 if (i != _channel_command_menu_map.end()) {
1586 boost::shared_ptr<MidiRegion>
1587 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1589 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1591 real_editor->begin_reversible_command (Operations::create_region);
1592 playlist()->clear_changes ();
1594 real_editor->snap_to (pos, 0);
1596 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1599 plist.add (ARDOUR::Properties::start, 0);
1600 plist.add (ARDOUR::Properties::length, length);
1601 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1603 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1605 playlist()->add_region (region, pos);
1606 _session->add_command (new StatefulDiffCommand (playlist()));
1609 real_editor->commit_reversible_command ();
1612 return boost::dynamic_pointer_cast<MidiRegion>(region);
1616 MidiTimeAxisView::ensure_step_editor ()
1618 if (!_step_editor) {
1619 _step_editor = new StepEditor (_editor, midi_track(), *this);
1624 MidiTimeAxisView::start_step_editing ()
1626 ensure_step_editor ();
1627 _step_editor->start_step_editing ();
1631 MidiTimeAxisView::stop_step_editing ()
1634 _step_editor->stop_step_editing ();
1638 /** @return channel (counted from 0) to add an event to, based on the current setting
1639 * of the channel selector.
1642 MidiTimeAxisView::get_channel_for_add () const
1644 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1646 uint8_t channel = 0;
1648 /* pick the highest selected channel, unless all channels are selected,
1649 which is interpreted to mean channel 1 (zero)
1652 for (uint16_t i = 0; i < 16; ++i) {
1653 if (chn_mask & (1<<i)) {
1659 if (chn_cnt == 16) {
1667 MidiTimeAxisView::note_range_changed ()
1669 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1670 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1674 MidiTimeAxisView::contents_height_changed ()
1676 _range_scroomer->queue_resize ();
1680 MidiTimeAxisView::playback_channel_mode_changed ()
1682 switch (midi_track()->get_playback_channel_mode()) {
1684 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1686 case FilterChannels:
1687 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1690 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1696 MidiTimeAxisView::capture_channel_mode_changed ()
1698 switch (midi_track()->get_capture_channel_mode()) {
1700 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1702 case FilterChannels:
1703 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1706 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));