2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/profile.h"
54 #include "ardour/region.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_object.h"
59 #include "ardour/source.h"
60 #include "ardour/track.h"
61 #include "ardour/types.h"
63 #include "ardour_ui.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
88 #include "note_base.h"
90 #include "ardour/midi_track.h"
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
101 // Minimum height at which a control is displayed
102 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
103 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
105 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
106 : AxisView(sess) // virtually inherited
107 , RouteTimeAxisView(ed, sess, canvas)
108 , _ignore_signals(false)
110 , _piano_roll_header(0)
111 , _note_mode(Sustained)
113 , _percussion_mode_item(0)
114 , _color_mode(MeterColors)
115 , _meter_color_mode_item(0)
116 , _channel_color_mode_item(0)
117 , _track_color_mode_item(0)
118 , _channel_selector (0)
119 , _step_edit_item (0)
120 , controller_menu (0)
126 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
130 _view = new MidiStreamView (*this);
133 _piano_roll_header = new PianoRollHeader(*midi_view());
134 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
135 _range_scroomer->DoubleClicked.connect (
136 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
137 MidiStreamView::ContentsRange, false));
140 /* This next call will result in our height being set up, so it must come after
141 the creation of the piano roll / range scroomer as their visibility is set up
144 RouteTimeAxisView::set_route (rt);
146 _view->apply_color (_color, StreamView::RegionColor);
148 subplugin_menu.set_name ("ArdourContextMenu");
150 if (!gui_property ("note-range-min").empty ()) {
151 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
152 atoi (gui_property ("note-range-max").c_str()),
156 midi_view()->NoteRangeChanged.connect (
157 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
158 _view->ContentsHeightChanged.connect (
159 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
161 ignore_toggle = false;
163 if (is_midi_track()) {
164 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
165 time_axis_frame.set_name ("MidiTimeAxisViewControlsBaseUnselected");
166 _note_mode = midi_track()->note_mode();
167 } else { // MIDI bus (which doesn't exist yet..)
168 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
169 time_axis_frame.set_name ("MidiBusControlsBaseUnselected");
172 /* if set_state above didn't create a gain automation child, we need to make one */
173 if (automation_child (GainAutomation) == 0) {
174 create_automation_child (GainAutomation, false);
177 /* if set_state above didn't create a mute automation child, we need to make one */
178 if (automation_child (MuteAutomation) == 0) {
179 create_automation_child (MuteAutomation, false);
182 if (_route->panner_shell()) {
183 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
186 /* map current state of the route */
187 ensure_pan_views (false);
189 processors_changed (RouteProcessorChange ());
191 _route->processors_changed.connect (*this, invalidator (*this),
192 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
196 _piano_roll_header->SetNoteSelection.connect (
197 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
198 _piano_roll_header->AddNoteSelection.connect (
199 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
200 _piano_roll_header->ExtendNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
202 _piano_roll_header->ToggleNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
205 /* Suspend updates of the StreamView during scroomer drags to speed things up */
206 _range_scroomer->DragStarting.connect (
207 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
208 _range_scroomer->DragFinishing.connect (
209 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
211 /* Put the scroomer and the keyboard in a VBox with a padding
212 label so that they can be reduced in height for stacked-view
216 HSeparator* separator = manage (new HSeparator());
217 separator->set_name("TrackSeparator");
218 separator->set_size_request(-1, 1);
221 VBox* v = manage (new VBox);
222 HBox* h = manage (new HBox);
223 h->pack_end (*_piano_roll_header);
224 h->pack_end (*_range_scroomer);
225 v->pack_start (*separator, false, false);
226 v->pack_start (*h, true, true);
229 top_hbox.remove(scroomer_placeholder);
230 time_axis_hbox.pack_end(*v, false, false, 0);
231 midi_scroomer_size_group->add_widget (*v);
233 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
234 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
235 controls_base_selected_name = "MidiTrackControlsBaseSelected";
236 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
238 midi_view()->NoteRangeChanged.connect (
239 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
241 /* ask for notifications of any new RegionViews */
242 _view->RegionViewAdded.connect (
243 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
245 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
246 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
248 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
249 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
251 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
252 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
254 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
255 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
258 playback_channel_mode_changed ();
259 capture_channel_mode_changed ();
261 if (!_editor.have_idled()) {
262 /* first idle will do what we need */
268 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
270 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
271 for (; m != patch_manager.all_models().end(); ++m) {
272 _midnam_model_selector.append_text(m->c_str());
275 if (gui_property (X_("midnam-model-name")).empty()) {
276 set_gui_property (X_("midnam-model-name"), "Generic");
279 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
280 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
282 set_gui_property (X_("midnam-custom-device-mode"),
283 *device_names->custom_device_mode_names().begin());
287 _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
288 _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
290 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
291 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
293 _midi_controls_box.set_homogeneous(false);
294 _midi_controls_box.set_border_width (2);
296 _channel_status_box.set_homogeneous (false);
297 _channel_status_box.set_spacing (4);
299 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
300 channel_selector_button->set_name ("route button");
301 ARDOUR_UI::instance()->set_tip (channel_selector_button, _("Click to edit channel settings"));
303 /* fixed sized labels to prevent silly nonsense (though obviously,
304 * they cause their own too)
306 set_size_request_to_display_given_text(_playback_channel_status, "Play: somemo", 2, 2); // TODO use _("Play: all/some")
307 set_size_request_to_display_given_text(_capture_channel_status, "Rec: somemo", 2, 2); // TODO use _("Rec: all/some")
309 _channel_status_box.pack_start (_playback_channel_status, false, false);
310 _channel_status_box.pack_start (_capture_channel_status, false, false);
311 _channel_status_box.pack_end (*channel_selector_button, false, false);
312 _channel_status_box.show_all ();
314 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
316 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
318 if (!patch_manager.all_models().empty()) {
320 _midnam_model_selector.show ();
321 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
323 _midnam_custom_device_mode_selector.show ();
325 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
329 custom_device_mode_changed();
331 _midnam_model_selector.signal_changed().connect(
332 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
333 _midnam_custom_device_mode_selector.signal_changed().connect(
334 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
336 controls_vbox.pack_start(_midi_controls_box, false, false);
338 const string color_mode = gui_property ("color-mode");
339 if (!color_mode.empty()) {
340 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
341 if (_channel_selector && _color_mode == ChannelColors) {
342 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
346 set_color_mode (_color_mode, true, false);
348 const string note_mode = gui_property ("note-mode");
349 if (!note_mode.empty()) {
350 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
351 if (_percussion_mode_item) {
352 _percussion_mode_item->set_active (_note_mode == Percussive);
356 /* Look for any GUI object state nodes that represent automation children
357 * that should exist, and create the children.
360 const list<string> gui_ids = gui_object_state().all_ids ();
361 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
364 Evoral::Parameter parameter (0, 0, 0);
366 bool const p = AutomationTimeAxisView::parse_state_id (
367 *i, route_id, has_parameter, parameter);
368 if (p && route_id == _route->id () && has_parameter) {
369 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
370 create_automation_child (parameter, string_is_affirmative (visible));
376 MidiTimeAxisView::first_idle ()
383 MidiTimeAxisView::~MidiTimeAxisView ()
385 delete _channel_selector;
387 delete _piano_roll_header;
388 _piano_roll_header = 0;
390 delete _range_scroomer;
393 delete controller_menu;
398 MidiTimeAxisView::enter_internal_edit_mode ()
401 midi_view()->enter_internal_edit_mode ();
406 MidiTimeAxisView::leave_internal_edit_mode ()
409 midi_view()->leave_internal_edit_mode ();
414 MidiTimeAxisView::check_step_edit ()
416 ensure_step_editor ();
417 _step_editor->check_step_edit ();
421 MidiTimeAxisView::model_changed()
423 const Glib::ustring model = _midnam_model_selector.get_active_text();
424 set_gui_property (X_("midnam-model-name"), model);
426 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
427 .custom_device_mode_names_by_model(model);
429 _midnam_custom_device_mode_selector.clear_items();
431 for (std::list<std::string>::const_iterator i = device_modes.begin();
432 i != device_modes.end(); ++i) {
433 _midnam_custom_device_mode_selector.append_text(*i);
436 _midnam_custom_device_mode_selector.set_active(0);
438 _route->instrument_info().set_external_instrument (
439 _midnam_model_selector.get_active_text(),
440 _midnam_custom_device_mode_selector.get_active_text());
442 // Rebuild controller menu
443 _controller_menu_map.clear ();
444 delete controller_menu;
446 build_automation_action_menu(false);
450 MidiTimeAxisView::custom_device_mode_changed()
452 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
453 set_gui_property (X_("midnam-custom-device-mode"), mode);
454 _route->instrument_info().set_external_instrument (
455 _midnam_model_selector.get_active_text(), mode);
459 MidiTimeAxisView::midi_view()
461 return dynamic_cast<MidiStreamView*>(_view);
465 MidiTimeAxisView::set_height (uint32_t h)
467 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
468 _midi_controls_box.show ();
470 _midi_controls_box.hide();
473 if (h >= KEYBOARD_MIN_HEIGHT) {
474 if (is_track() && _range_scroomer) {
475 _range_scroomer->show();
477 if (is_track() && _piano_roll_header) {
478 _piano_roll_header->show();
481 if (is_track() && _range_scroomer) {
482 _range_scroomer->hide();
484 if (is_track() && _piano_roll_header) {
485 _piano_roll_header->hide();
489 /* We need to do this after changing visibility of our stuff, as it will
490 eventually trigger a call to Editor::reset_controls_layout_width(),
491 which needs to know if we have just shown or hidden a scroomer /
494 RouteTimeAxisView::set_height (h);
498 MidiTimeAxisView::append_extra_display_menu_items ()
500 using namespace Menu_Helpers;
502 MenuList& items = display_menu->items();
505 Menu *range_menu = manage(new Menu);
506 MenuList& range_items = range_menu->items();
507 range_menu->set_name ("ArdourContextMenu");
509 range_items.push_back (
510 MenuElem (_("Show Full Range"),
511 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
512 MidiStreamView::FullRange, true)));
514 range_items.push_back (
515 MenuElem (_("Fit Contents"),
516 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
517 MidiStreamView::ContentsRange, true)));
519 items.push_back (MenuElem (_("Note Range"), *range_menu));
520 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
521 items.push_back (MenuElem (_("Channel Selector"),
522 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
524 color_mode_menu = build_color_mode_menu();
525 if (color_mode_menu) {
526 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
529 items.push_back (SeparatorElem ());
533 MidiTimeAxisView::toggle_channel_selector ()
535 if (!_channel_selector) {
536 _channel_selector = new MidiChannelSelectorWindow (midi_track());
538 if (_color_mode == ChannelColors) {
539 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
541 _channel_selector->set_default_channel_color ();
544 _channel_selector->show_all ();
546 _channel_selector->cycle_visibility ();
551 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
553 using namespace Menu_Helpers;
555 /* If we have a controller menu, we need to detach it before
556 RouteTimeAxis::build_automation_action_menu destroys the
557 menu it is attached to. Otherwise GTK destroys
558 controller_menu's gobj, meaning that it can't be reattached
559 below. See bug #3134.
562 if (controller_menu) {
563 detach_menu (*controller_menu);
566 _channel_command_menu_map.clear ();
567 RouteTimeAxisView::build_automation_action_menu (for_selection);
569 MenuList& automation_items = automation_action_menu->items();
571 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
573 if (selected_channels != 0) {
575 automation_items.push_back (SeparatorElem());
577 /* these 2 MIDI "command" types are semantically more like automation
578 than note data, but they are not MIDI controllers. We give them
579 special status in this menu, since they will not show up in the
580 controller list and anyone who actually knows something about MIDI
581 (!) would not expect to find them there.
584 add_channel_command_menu_item (
585 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
586 automation_items.back().set_sensitive (
587 !for_selection || _editor.get_selection().tracks.size() == 1);
588 add_channel_command_menu_item (
589 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
590 automation_items.back().set_sensitive (
591 !for_selection || _editor.get_selection().tracks.size() == 1);
593 /* now all MIDI controllers. Always offer the possibility that we will
594 rebuild the controllers menu since it might need to be updated after
595 a channel mode change or other change. Also detach it first in case
596 it has been used anywhere else.
599 build_controller_menu ();
601 automation_items.push_back (SeparatorElem());
602 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
603 automation_items.back().set_sensitive (
604 !for_selection || _editor.get_selection().tracks.size() == 1);
606 automation_items.push_back (
607 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
608 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
611 automation_items.push_back (SeparatorElem());
612 automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility)));
613 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
614 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
615 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
617 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
619 if (!pan_tracks.empty()) {
620 automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility)));
621 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
622 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
623 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
625 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
626 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
627 _main_automation_menu_map[*p] = pan_automation_item;
634 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
636 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
638 for (uint8_t chn = 0; chn < 16; chn++) {
639 if (selected_channels & (0x0001 << chn)) {
641 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
642 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
645 menu->set_active (yn);
652 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
654 AutomationType auto_type,
657 using namespace Menu_Helpers;
659 /* count the number of selected channels because we will build a different menu
660 structure if there is more than 1 selected.
663 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
666 for (uint8_t chn = 0; chn < 16; chn++) {
667 if (selected_channels & (0x0001 << chn)) {
676 /* multiple channels - create a submenu, with 1 item per channel */
678 Menu* chn_menu = manage (new Menu);
679 MenuList& chn_items (chn_menu->items());
680 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
682 /* add a couple of items to hide/show all of them */
684 chn_items.push_back (
685 MenuElem (_("Hide all channels"),
686 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
687 false, param_without_channel)));
688 chn_items.push_back (
689 MenuElem (_("Show all channels"),
690 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
691 true, param_without_channel)));
693 for (uint8_t chn = 0; chn < 16; chn++) {
694 if (selected_channels & (0x0001 << chn)) {
696 /* for each selected channel, add a menu item for this controller */
698 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
699 chn_items.push_back (
700 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
701 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
702 fully_qualified_param)));
704 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
705 bool visible = false;
708 if (track->marked_for_display()) {
713 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
714 _channel_command_menu_map[fully_qualified_param] = cmi;
715 cmi->set_active (visible);
719 /* now create an item in the parent menu that has the per-channel list as a submenu */
721 items.push_back (MenuElem (label, *chn_menu));
725 /* just one channel - create a single menu item for this command+channel combination*/
727 for (uint8_t chn = 0; chn < 16; chn++) {
728 if (selected_channels & (0x0001 << chn)) {
730 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
732 CheckMenuElem (label,
733 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
734 fully_qualified_param)));
736 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
737 bool visible = false;
740 if (track->marked_for_display()) {
745 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
746 _channel_command_menu_map[fully_qualified_param] = cmi;
747 cmi->set_active (visible);
749 /* one channel only */
756 /** Add a single menu item for a controller on one channel. */
758 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
760 const std::string& name)
762 using namespace Menu_Helpers;
764 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
765 for (uint8_t chn = 0; chn < 16; chn++) {
766 if (selected_channels & (0x0001 << chn)) {
768 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
769 ctl_items.push_back (
771 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
773 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
774 fully_qualified_param)));
775 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
777 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
778 fully_qualified_param);
780 bool visible = false;
782 if (track->marked_for_display()) {
787 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
788 _controller_menu_map[fully_qualified_param] = cmi;
789 cmi->set_active (visible);
791 /* one channel only */
797 /** Add a submenu with 1 item per channel for a controller on many channels. */
799 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
801 const std::string& name)
803 using namespace Menu_Helpers;
805 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
807 Menu* chn_menu = manage (new Menu);
808 MenuList& chn_items (chn_menu->items());
810 /* add a couple of items to hide/show this controller on all channels */
812 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
813 chn_items.push_back (
814 MenuElem (_("Hide all channels"),
815 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
816 false, param_without_channel)));
817 chn_items.push_back (
818 MenuElem (_("Show all channels"),
819 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
820 true, param_without_channel)));
822 for (uint8_t chn = 0; chn < 16; chn++) {
823 if (selected_channels & (0x0001 << chn)) {
825 /* for each selected channel, add a menu item for this controller */
827 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
828 chn_items.push_back (
829 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
830 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
831 fully_qualified_param)));
833 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
834 fully_qualified_param);
835 bool visible = false;
838 if (track->marked_for_display()) {
843 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
844 _controller_menu_map[fully_qualified_param] = cmi;
845 cmi->set_active (visible);
849 /* add the per-channel menu to the list of controllers, with the name of the controller */
850 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
852 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
855 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
856 MidiTimeAxisView::get_device_mode()
858 using namespace MIDI::Name;
860 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
862 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
865 return device_names->custom_device_mode_by_name(
866 gui_property (X_("midnam-custom-device-mode")));
869 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
870 MidiTimeAxisView::get_device_names()
872 using namespace MIDI::Name;
874 const std::string model = gui_property (X_("midnam-model-name"));
876 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
877 .document_by_model(model);
879 return midnam->master_device_names(model);
881 return boost::shared_ptr<MasterDeviceNames>();
886 MidiTimeAxisView::build_controller_menu ()
888 using namespace Menu_Helpers;
890 if (controller_menu) {
891 /* it exists and has not been invalidated by a channel mode change */
895 controller_menu = new Menu; // explicitly managed by us
896 MenuList& items (controller_menu->items());
898 /* create several "top level" menu items for sets of controllers (16 at a
899 time), and populate each one with a submenu for each controller+channel
900 combination covering the currently selected channels for this track
903 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
905 /* count the number of selected channels because we will build a different menu
906 structure if there is more than 1 selected.
910 for (uint8_t chn = 0; chn < 16; chn++) {
911 if (selected_channels & (0x0001 << chn)) {
918 using namespace MIDI::Name;
919 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
921 if (device_names && !device_names->controls().empty()) {
922 /* Controllers names available in midnam file, generate fancy menu */
923 unsigned n_items = 0;
924 unsigned n_groups = 0;
926 /* TODO: This is not correct, should look up the currently applicable ControlNameList
927 and only build a menu for that one. */
928 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
929 l != device_names->controls().end(); ++l) {
930 boost::shared_ptr<ControlNameList> name_list = l->second;
931 Menu* ctl_menu = NULL;
933 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
934 c != name_list->controls().end();) {
935 const uint16_t ctl = c->second->number();
936 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
937 /* Skip bank select controllers since they're handled specially */
939 /* Create a new submenu */
940 ctl_menu = manage (new Menu);
943 MenuList& ctl_items (ctl_menu->items());
945 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
947 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
952 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
953 /* Submenu has 16 items or we're done, add it to controller menu and reset */
955 MenuElem(string_compose(_("Controllers %1-%2"),
956 (16 * n_groups), (16 * n_groups) + n_items - 1),
965 /* No controllers names, generate generic numeric menu */
966 for (int i = 0; i < 127; i += 16) {
967 Menu* ctl_menu = manage (new Menu);
968 MenuList& ctl_items (ctl_menu->items());
970 for (int ctl = i; ctl < i+16; ++ctl) {
971 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
972 /* Skip bank select controllers since they're handled specially */
977 add_multi_channel_controller_item(
978 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
980 add_single_channel_controller_item(
981 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
985 /* Add submenu for this block of controllers to controller menu */
987 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
994 MidiTimeAxisView::build_note_mode_menu()
996 using namespace Menu_Helpers;
998 Menu* mode_menu = manage (new Menu);
999 MenuList& items = mode_menu->items();
1000 mode_menu->set_name ("ArdourContextMenu");
1002 RadioMenuItem::Group mode_group;
1004 RadioMenuElem (mode_group,_("Sustained"),
1005 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1007 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1008 _note_mode_item->set_active(_note_mode == Sustained);
1011 RadioMenuElem (mode_group, _("Percussive"),
1012 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1013 Percussive, true)));
1014 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1015 _percussion_mode_item->set_active(_note_mode == Percussive);
1021 MidiTimeAxisView::build_color_mode_menu()
1023 using namespace Menu_Helpers;
1025 Menu* mode_menu = manage (new Menu);
1026 MenuList& items = mode_menu->items();
1027 mode_menu->set_name ("ArdourContextMenu");
1029 RadioMenuItem::Group mode_group;
1031 RadioMenuElem (mode_group, _("Meter Colors"),
1032 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1033 MeterColors, false, true, true)));
1034 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1035 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1038 RadioMenuElem (mode_group, _("Channel Colors"),
1039 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1040 ChannelColors, false, true, true)));
1041 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1042 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1045 RadioMenuElem (mode_group, _("Track Color"),
1046 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1047 TrackColor, false, true, true)));
1048 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1049 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1055 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1057 if (apply_to_selection) {
1058 _editor.get_selection().tracks.foreach_midi_time_axis (
1059 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1061 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1063 midi_track()->set_note_mode(mode);
1064 set_gui_property ("note-mode", enum_2_string(_note_mode));
1065 _view->redisplay_track();
1071 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1073 if (apply_to_selection) {
1074 _editor.get_selection().tracks.foreach_midi_time_axis (
1075 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1077 if (_color_mode == mode && !force) {
1081 if (_channel_selector) {
1082 if (mode == ChannelColors) {
1083 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1085 _channel_selector->set_default_channel_color();
1090 set_gui_property ("color-mode", enum_2_string(_color_mode));
1092 _view->redisplay_track();
1098 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1100 if (apply_to_selection) {
1101 _editor.get_selection().tracks.foreach_midi_time_axis (
1102 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1104 if (!_ignore_signals) {
1105 midi_view()->set_note_range(range);
1111 MidiTimeAxisView::update_range()
1113 MidiGhostRegion* mgr;
1115 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1116 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1117 mgr->update_range();
1123 MidiTimeAxisView::ensure_pan_views (bool show)
1125 bool changed = false;
1126 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1128 (*i)->set_marked_for_display (false);
1131 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1135 if (!_route->panner()) {
1139 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1140 set<Evoral::Parameter>::iterator p;
1142 for (p = params.begin(); p != params.end(); ++p) {
1143 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1145 if (pan_control->parameter().type() == NullAutomation) {
1146 error << "Pan control has NULL automation type!" << endmsg;
1150 if (automation_child (pan_control->parameter ()).get () == 0) {
1152 /* we don't already have an AutomationTimeAxisView for this parameter */
1154 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1156 boost::shared_ptr<AutomationTimeAxisView> t (
1157 new AutomationTimeAxisView (_session,
1161 pan_control->parameter (),
1169 pan_tracks.push_back (t);
1170 add_automation_child (*p, t, show);
1172 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1178 MidiTimeAxisView::update_gain_track_visibility ()
1180 bool const showit = gain_automation_item->get_active();
1182 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1183 gain_track->set_marked_for_display (showit);
1185 /* now trigger a redisplay */
1188 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1194 MidiTimeAxisView::update_pan_track_visibility ()
1196 bool const showit = pan_automation_item->get_active();
1197 bool changed = false;
1199 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1200 if ((*i)->set_marked_for_display (showit)) {
1206 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1211 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1213 using namespace MIDI::Name;
1215 if (apply_to_selection) {
1216 _editor.get_selection().tracks.foreach_midi_time_axis (
1217 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1220 // Show existing automation
1221 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1223 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1224 create_automation_child(*i, true);
1227 // Show automation for all controllers named in midnam file
1228 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1229 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1230 device_names && !device_names->controls().empty()) {
1231 const std::string device_mode = _midnam_custom_device_mode_selector.get_active_text();
1232 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1233 for (uint32_t chn = 0; chn < 16; ++chn) {
1234 if ((selected_channels & (0x0001 << chn)) == 0) {
1235 // Channel not in use
1239 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1245 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1246 chan_names->control_list_name());
1247 if (!control_names) {
1251 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1252 c != control_names->controls().end();
1254 const uint16_t ctl = c->second->number();
1255 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1256 /* Skip bank select controllers since they're handled specially */
1257 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1258 create_automation_child(param, true);
1265 RouteTimeAxisView::show_all_automation ();
1270 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1272 if (apply_to_selection) {
1273 _editor.get_selection().tracks.foreach_midi_time_axis (
1274 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1277 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1279 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1280 create_automation_child (*i, true);
1284 RouteTimeAxisView::show_existing_automation ();
1288 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1291 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1293 if (param.type() == NullAutomation) {
1297 AutomationTracks::iterator existing = _automation_tracks.find (param);
1299 if (existing != _automation_tracks.end()) {
1301 /* automation track created because we had existing data for
1302 * the processor, but visibility may need to be controlled
1303 * since it will have been set visible by default.
1306 existing->second->set_marked_for_display (show);
1315 boost::shared_ptr<AutomationTimeAxisView> track;
1316 boost::shared_ptr<AutomationControl> control;
1319 switch (param.type()) {
1321 case GainAutomation:
1322 create_gain_automation_child (param, show);
1325 case MuteAutomation:
1326 create_mute_automation_child (param, show);
1329 case PluginAutomation:
1330 /* handled elsewhere */
1333 case MidiCCAutomation:
1334 case MidiPgmChangeAutomation:
1335 case MidiPitchBenderAutomation:
1336 case MidiChannelPressureAutomation:
1337 case MidiSystemExclusiveAutomation:
1338 /* These controllers are region "automation" - they are owned
1339 * by regions (and their MidiModels), not by the track. As a
1340 * result there is no AutomationList/Line for the track, but we create
1341 * a controller for the user to write immediate events, so the editor
1342 * can act as a control surface for the present MIDI controllers.
1344 * TODO: Record manipulation of the controller to regions?
1347 control = _route->automation_control(param, true);
1348 track.reset (new AutomationTimeAxisView (
1351 control ? _route : boost::shared_ptr<Automatable> (),
1358 _route->describe_parameter(param)));
1361 _view->foreach_regionview (
1362 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1365 add_automation_child (param, track, show);
1368 case PanWidthAutomation:
1369 case PanElevationAutomation:
1370 case PanAzimuthAutomation:
1371 ensure_pan_views (show);
1375 error << "MidiTimeAxisView: unknown automation child "
1376 << EventTypeMap::instance().to_symbol(param) << endmsg;
1381 MidiTimeAxisView::route_active_changed ()
1383 RouteUI::route_active_changed ();
1386 if (_route->active()) {
1387 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1388 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1389 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1390 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1392 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1393 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1394 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1395 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1398 if (_route->active()) {
1399 controls_ebox.set_name ("BusControlsBaseUnselected");
1400 time_axis_frame.set_name ("BusControlsBaseUnselected");
1401 controls_base_selected_name = "BusControlsBaseSelected";
1402 controls_base_unselected_name = "BusControlsBaseUnselected";
1404 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1405 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1406 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1407 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1413 MidiTimeAxisView::set_note_selection (uint8_t note)
1415 if (!_editor.internal_editing()) {
1419 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1421 if (_view->num_selected_regionviews() == 0) {
1422 _view->foreach_regionview (
1423 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1426 _view->foreach_selected_regionview (
1427 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1433 MidiTimeAxisView::add_note_selection (uint8_t note)
1435 if (!_editor.internal_editing()) {
1439 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1441 if (_view->num_selected_regionviews() == 0) {
1442 _view->foreach_regionview (
1443 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1446 _view->foreach_selected_regionview (
1447 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1453 MidiTimeAxisView::extend_note_selection (uint8_t note)
1455 if (!_editor.internal_editing()) {
1459 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1461 if (_view->num_selected_regionviews() == 0) {
1462 _view->foreach_regionview (
1463 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1466 _view->foreach_selected_regionview (
1467 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1473 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1475 if (!_editor.internal_editing()) {
1479 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1481 if (_view->num_selected_regionviews() == 0) {
1482 _view->foreach_regionview (
1483 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1486 _view->foreach_selected_regionview (
1487 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1493 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1495 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1499 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1501 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1505 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1507 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1511 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1513 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1517 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1519 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1523 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1524 bool changed = false;
1528 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1530 for (uint32_t chn = 0; chn < 16; ++chn) {
1531 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1532 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1538 if ((selected_channels & (0x0001 << chn)) == 0) {
1539 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1540 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1542 changed = track->set_marked_for_display (false) || changed;
1544 changed = track->set_marked_for_display (true) || changed;
1551 /* TODO: Bender, Pressure */
1553 /* invalidate the controller menu, so that we rebuild it next time */
1554 _controller_menu_map.clear ();
1555 delete controller_menu;
1556 controller_menu = 0;
1564 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1566 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1571 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1572 if (i != _controller_menu_map.end()) {
1576 i = _channel_command_menu_map.find (param);
1577 if (i != _channel_command_menu_map.end()) {
1584 boost::shared_ptr<MidiRegion>
1585 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1587 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1589 real_editor->begin_reversible_command (Operations::create_region);
1590 playlist()->clear_changes ();
1592 real_editor->snap_to (pos, RoundNearest);
1594 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1597 plist.add (ARDOUR::Properties::start, 0);
1598 plist.add (ARDOUR::Properties::length, length);
1599 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1601 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1603 playlist()->add_region (region, pos);
1604 _session->add_command (new StatefulDiffCommand (playlist()));
1607 real_editor->commit_reversible_command ();
1610 return boost::dynamic_pointer_cast<MidiRegion>(region);
1614 MidiTimeAxisView::ensure_step_editor ()
1616 if (!_step_editor) {
1617 _step_editor = new StepEditor (_editor, midi_track(), *this);
1622 MidiTimeAxisView::start_step_editing ()
1624 ensure_step_editor ();
1625 _step_editor->start_step_editing ();
1629 MidiTimeAxisView::stop_step_editing ()
1632 _step_editor->stop_step_editing ();
1636 /** @return channel (counted from 0) to add an event to, based on the current setting
1637 * of the channel selector.
1640 MidiTimeAxisView::get_channel_for_add () const
1642 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1644 uint8_t channel = 0;
1646 /* pick the highest selected channel, unless all channels are selected,
1647 which is interpreted to mean channel 1 (zero)
1650 for (uint16_t i = 0; i < 16; ++i) {
1651 if (chn_mask & (1<<i)) {
1657 if (chn_cnt == 16) {
1665 MidiTimeAxisView::note_range_changed ()
1667 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1668 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1672 MidiTimeAxisView::contents_height_changed ()
1674 _range_scroomer->queue_resize ();
1678 MidiTimeAxisView::playback_channel_mode_changed ()
1680 switch (midi_track()->get_playback_channel_mode()) {
1682 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1684 case FilterChannels:
1685 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1688 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1694 MidiTimeAxisView::capture_channel_mode_changed ()
1696 switch (midi_track()->get_capture_channel_mode()) {
1698 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1700 case FilterChannels:
1701 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1704 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));