Factor out duplicated track automation code.
[ardour.git] / gtk2_ardour / midi_time_axis.cc
1 /*
2     Copyright (C) 2000 Paul Davis
3
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.
8
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.
13
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.
17 */
18
19 #include <cstdlib>
20 #include <cmath>
21
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25
26 #include <sigc++/bind.h>
27
28 #include "pbd/error.h"
29 #include "pbd/ffs.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"
36
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
41
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"
62
63 #include "ardour_ui.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
67 #include "editor.h"
68 #include "enums.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
71 #include "keyboard.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"
82 #include "prompter.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
87 #include "utils.h"
88 #include "note_base.h"
89
90 #include "ardour/midi_track.h"
91
92 #include "i18n.h"
93
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
96 using namespace PBD;
97 using namespace Gtk;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
100
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;
104
105 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
106         : AxisView(sess) // virtually inherited
107         , RouteTimeAxisView(ed, sess, canvas)
108         , _ignore_signals(false)
109         , _range_scroomer(0)
110         , _piano_roll_header(0)
111         , _note_mode(Sustained)
112         , _note_mode_item(0)
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)
121         , _step_editor (0)
122 {
123 }
124
125 void
126 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
127 {
128         _route = rt;
129         
130         _view = new MidiStreamView (*this);
131
132         if (is_track ()) {
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));
138         }
139
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
142            when our height is.
143         */
144         RouteTimeAxisView::set_route (rt);
145
146         _view->apply_color (_color, StreamView::RegionColor);
147
148         subplugin_menu.set_name ("ArdourContextMenu");
149
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()),
153                                                true);
154         }
155
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));
160
161         ignore_toggle = false;
162
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");
170         }
171
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);
175         }
176
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);
180         }
181
182         if (_route->panner_shell()) {
183                 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
184         }
185
186         /* map current state of the route */
187         ensure_pan_views (false);
188
189         processors_changed (RouteProcessorChange ());
190
191         _route->processors_changed.connect (*this, invalidator (*this),
192                                             boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
193                                             gui_context());
194
195         if (is_track()) {
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));
204
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));
210
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
213                    tracks.
214                 */
215
216                 HSeparator* separator = manage (new HSeparator());
217                 separator->set_name("TrackSeparator");
218                 separator->set_size_request(-1, 1);
219                 separator->show();
220
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);
227                 v->show ();
228                 h->show ();
229                 top_hbox.remove(scroomer_placeholder);
230                 time_axis_hbox.pack_end(*v, false, false, 0);
231                 midi_scroomer_size_group->add_widget (*v);
232
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";
237
238                 midi_view()->NoteRangeChanged.connect (
239                         sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
240
241                 /* ask for notifications of any new RegionViews */
242                 _view->RegionViewAdded.connect (
243                         sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
244
245                 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
246                                                                   boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
247                                                                   gui_context());
248                 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
249                                                                   boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
250                                                                   gui_context());
251                 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
252                                                                   boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
253                                                                   gui_context());
254                 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
255                                                                   boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
256                                                                   gui_context());
257
258                 playback_channel_mode_changed ();
259                 capture_channel_mode_changed ();
260
261                 if (!_editor.have_idled()) {
262                         /* first idle will do what we need */
263                 } else {
264                         first_idle ();
265                 }
266         }
267
268         MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
269
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());
273         }
274
275         if (gui_property (X_("midnam-model-name")).empty()) {
276                 set_gui_property (X_("midnam-model-name"), "Generic");
277         }
278
279         if (gui_property (X_("midnam-custom-device-mode")).empty()) {
280                 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
281                 if (device_names) {
282                         set_gui_property (X_("midnam-custom-device-mode"),
283                                           *device_names->custom_device_mode_names().begin());
284                 }
285         }
286
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")));
289
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"));
292
293         _midi_controls_box.set_homogeneous(false);
294         _midi_controls_box.set_border_width (2);
295
296         _channel_status_box.set_homogeneous (false);
297         _channel_status_box.set_spacing (4);
298         
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"));
302         
303         /* fixed sized labels to prevent silly nonsense (though obviously,
304          * they cause their own too)
305          */
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")
308
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 ();
313
314         channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
315         
316         _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
317
318         if (!patch_manager.all_models().empty()) {
319
320                 _midnam_model_selector.show ();
321                 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
322
323                 _midnam_custom_device_mode_selector.show ();
324
325                 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
326         } 
327
328         model_changed();
329         custom_device_mode_changed();
330
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));
335
336         controls_vbox.pack_start(_midi_controls_box, false, false);
337
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);
343                 }
344         }
345
346         set_color_mode (_color_mode, true, false);
347
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);
353                 }
354         }
355
356         /* Look for any GUI object state nodes that represent automation children
357          * that should exist, and create the children.
358          */
359
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) {
362                 PBD::ID route_id;
363                 bool has_parameter;
364                 Evoral::Parameter parameter (0, 0, 0);
365
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));
371                 }
372         }
373 }
374
375 void
376 MidiTimeAxisView::first_idle ()
377 {
378         if (is_track ()) {
379                 _view->attach ();
380         }
381 }
382
383 MidiTimeAxisView::~MidiTimeAxisView ()
384 {
385         delete _channel_selector;
386
387         delete _piano_roll_header;
388         _piano_roll_header = 0;
389
390         delete _range_scroomer;
391         _range_scroomer = 0;
392
393         delete controller_menu;
394         delete _step_editor;
395 }
396
397 void
398 MidiTimeAxisView::enter_internal_edit_mode ()
399 {
400         if (midi_view()) {
401                 midi_view()->enter_internal_edit_mode ();
402         }
403 }
404
405 void
406 MidiTimeAxisView::leave_internal_edit_mode ()
407 {
408         if (midi_view()) {
409                 midi_view()->leave_internal_edit_mode ();
410         }
411 }
412
413 void
414 MidiTimeAxisView::check_step_edit ()
415 {
416         ensure_step_editor ();
417         _step_editor->check_step_edit ();
418 }
419
420 void
421 MidiTimeAxisView::model_changed()
422 {
423         const Glib::ustring model = _midnam_model_selector.get_active_text();
424         set_gui_property (X_("midnam-model-name"), model);
425
426         const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
427                 .custom_device_mode_names_by_model(model);
428
429         _midnam_custom_device_mode_selector.clear_items();
430
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);
434         }
435
436         _midnam_custom_device_mode_selector.set_active(0);
437         
438         _route->instrument_info().set_external_instrument (
439                 _midnam_model_selector.get_active_text(),
440                 _midnam_custom_device_mode_selector.get_active_text());
441
442         // Rebuild controller menu
443         _controller_menu_map.clear ();
444         delete controller_menu;
445         controller_menu = 0;
446         build_automation_action_menu(false);
447 }
448
449 void
450 MidiTimeAxisView::custom_device_mode_changed()
451 {
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);
456 }
457
458 MidiStreamView*
459 MidiTimeAxisView::midi_view()
460 {
461         return dynamic_cast<MidiStreamView*>(_view);
462 }
463
464 void
465 MidiTimeAxisView::set_height (uint32_t h)
466 {
467         if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
468                 _midi_controls_box.show ();
469         } else {
470                 _midi_controls_box.hide();
471         }
472         
473         if (h >= KEYBOARD_MIN_HEIGHT) {
474                 if (is_track() && _range_scroomer) {
475                         _range_scroomer->show();
476                 }
477                 if (is_track() && _piano_roll_header) {
478                         _piano_roll_header->show();
479                 }
480         } else {
481                 if (is_track() && _range_scroomer) {
482                         _range_scroomer->hide();
483                 }
484                 if (is_track() && _piano_roll_header) {
485                         _piano_roll_header->hide();
486                 }
487         }
488
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 /
492            piano roll.
493         */
494         RouteTimeAxisView::set_height (h);
495 }
496
497 void
498 MidiTimeAxisView::append_extra_display_menu_items ()
499 {
500         using namespace Menu_Helpers;
501
502         MenuList& items = display_menu->items();
503
504         // Note range
505         Menu *range_menu = manage(new Menu);
506         MenuList& range_items = range_menu->items();
507         range_menu->set_name ("ArdourContextMenu");
508
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)));
513
514         range_items.push_back (
515                 MenuElem (_("Fit Contents"),
516                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
517                                       MidiStreamView::ContentsRange, true)));
518
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)));
523
524         color_mode_menu = build_color_mode_menu();
525         if (color_mode_menu) {
526                 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
527         }
528         
529         items.push_back (SeparatorElem ());
530 }
531
532 void
533 MidiTimeAxisView::toggle_channel_selector ()
534 {
535         if (!_channel_selector) {
536                 _channel_selector = new MidiChannelSelectorWindow (midi_track());
537
538                 if (_color_mode == ChannelColors) {
539                         _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
540                 } else {
541                         _channel_selector->set_default_channel_color ();
542                 }
543
544                 _channel_selector->show_all ();
545         } else {
546                 _channel_selector->cycle_visibility ();
547         }
548 }
549
550 void
551 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
552 {
553         using namespace Menu_Helpers;
554
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.
560         */
561
562         if (controller_menu) {
563                 detach_menu (*controller_menu);
564         }
565
566         _channel_command_menu_map.clear ();
567         RouteTimeAxisView::build_automation_action_menu (for_selection);
568
569         MenuList& automation_items = automation_action_menu->items();
570
571         uint16_t selected_channels = midi_track()->get_playback_channel_mask();
572
573         if (selected_channels !=  0) {
574
575                 automation_items.push_back (SeparatorElem());
576
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.
582                 */
583
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);
592
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.
597                 */
598
599                 build_controller_menu ();
600
601                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
602                 automation_items.back().set_sensitive (
603                         !for_selection || _editor.get_selection().tracks.size() == 1);
604         } else {
605                 automation_items.push_back (
606                         MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
607                 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
608         }
609 }
610
611 void
612 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
613 {
614         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
615
616         for (uint8_t chn = 0; chn < 16; chn++) {
617                 if (selected_channels & (0x0001 << chn)) {
618
619                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
620                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
621
622                         if (menu) {
623                                 menu->set_active (yn);
624                         }
625                 }
626         }
627 }
628
629 void
630 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
631                                                  const string&           label,
632                                                  AutomationType          auto_type,
633                                                  uint8_t                 cmd)
634 {
635         using namespace Menu_Helpers;
636
637         /* count the number of selected channels because we will build a different menu
638            structure if there is more than 1 selected.
639          */
640
641         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
642         int chn_cnt = 0;
643
644         for (uint8_t chn = 0; chn < 16; chn++) {
645                 if (selected_channels & (0x0001 << chn)) {
646                         if (++chn_cnt > 1) {
647                                 break;
648                         }
649                 }
650         }
651
652         if (chn_cnt > 1) {
653
654                 /* multiple channels - create a submenu, with 1 item per channel */
655
656                 Menu* chn_menu = manage (new Menu);
657                 MenuList& chn_items (chn_menu->items());
658                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
659
660                 /* add a couple of items to hide/show all of them */
661
662                 chn_items.push_back (
663                         MenuElem (_("Hide all channels"),
664                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
665                                               false, param_without_channel)));
666                 chn_items.push_back (
667                         MenuElem (_("Show all channels"),
668                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
669                                               true, param_without_channel)));
670
671                 for (uint8_t chn = 0; chn < 16; chn++) {
672                         if (selected_channels & (0x0001 << chn)) {
673
674                                 /* for each selected channel, add a menu item for this controller */
675
676                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
677                                 chn_items.push_back (
678                                         CheckMenuElem (string_compose (_("Channel %1"), chn+1),
679                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
680                                                                    fully_qualified_param)));
681
682                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
683                                 bool visible = false;
684
685                                 if (track) {
686                                         if (track->marked_for_display()) {
687                                                 visible = true;
688                                         }
689                                 }
690
691                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
692                                 _channel_command_menu_map[fully_qualified_param] = cmi;
693                                 cmi->set_active (visible);
694                         }
695                 }
696
697                 /* now create an item in the parent menu that has the per-channel list as a submenu */
698
699                 items.push_back (MenuElem (label, *chn_menu));
700
701         } else {
702
703                 /* just one channel - create a single menu item for this command+channel combination*/
704
705                 for (uint8_t chn = 0; chn < 16; chn++) {
706                         if (selected_channels & (0x0001 << chn)) {
707
708                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
709                                 items.push_back (
710                                         CheckMenuElem (label,
711                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
712                                                                    fully_qualified_param)));
713
714                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
715                                 bool visible = false;
716
717                                 if (track) {
718                                         if (track->marked_for_display()) {
719                                                 visible = true;
720                                         }
721                                 }
722
723                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
724                                 _channel_command_menu_map[fully_qualified_param] = cmi;
725                                 cmi->set_active (visible);
726
727                                 /* one channel only */
728                                 break;
729                         }
730                 }
731         }
732 }
733
734 /** Add a single menu item for a controller on one channel. */
735 void
736 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
737                                                      int                     ctl,
738                                                      const std::string&      name)
739 {
740         using namespace Menu_Helpers;
741
742         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
743         for (uint8_t chn = 0; chn < 16; chn++) {
744                 if (selected_channels & (0x0001 << chn)) {
745
746                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
747                         ctl_items.push_back (
748                                 CheckMenuElem (
749                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
750                                         sigc::bind (
751                                                 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
752                                                 fully_qualified_param)));
753                         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
754
755                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
756                                 fully_qualified_param);
757
758                         bool visible = false;
759                         if (track) {
760                                 if (track->marked_for_display()) {
761                                         visible = true;
762                                 }
763                         }
764
765                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
766                         _controller_menu_map[fully_qualified_param] = cmi;
767                         cmi->set_active (visible);
768
769                         /* one channel only */
770                         break;
771                 }
772         }
773 }
774
775 /** Add a submenu with 1 item per channel for a controller on many channels. */
776 void
777 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
778                                                     int                     ctl,
779                                                     const std::string&      name)
780 {
781         using namespace Menu_Helpers;
782
783         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
784
785         Menu* chn_menu = manage (new Menu);
786         MenuList& chn_items (chn_menu->items());
787
788         /* add a couple of items to hide/show this controller on all channels */
789
790         Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
791         chn_items.push_back (
792                 MenuElem (_("Hide all channels"),
793                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
794                                       false, param_without_channel)));
795         chn_items.push_back (
796                 MenuElem (_("Show all channels"),
797                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
798                                       true, param_without_channel)));
799
800         for (uint8_t chn = 0; chn < 16; chn++) {
801                 if (selected_channels & (0x0001 << chn)) {
802
803                         /* for each selected channel, add a menu item for this controller */
804
805                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
806                         chn_items.push_back (
807                                 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
808                                                sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
809                                                            fully_qualified_param)));
810
811                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
812                                 fully_qualified_param);
813                         bool visible = false;
814
815                         if (track) {
816                                 if (track->marked_for_display()) {
817                                         visible = true;
818                                 }
819                         }
820
821                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
822                         _controller_menu_map[fully_qualified_param] = cmi;
823                         cmi->set_active (visible);
824                 }
825         }
826
827         /* add the per-channel menu to the list of controllers, with the name of the controller */
828         ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
829                                        *chn_menu));
830         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
831 }
832
833 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
834 MidiTimeAxisView::get_device_mode()
835 {
836         using namespace MIDI::Name;
837
838         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
839         if (!device_names) {
840                 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
841         }
842
843         return device_names->custom_device_mode_by_name(
844                 gui_property (X_("midnam-custom-device-mode")));
845 }
846
847 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
848 MidiTimeAxisView::get_device_names()
849 {
850         using namespace MIDI::Name;
851
852         const std::string model = gui_property (X_("midnam-model-name"));
853
854         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
855                 .document_by_model(model);
856         if (midnam) {
857                 return midnam->master_device_names(model);
858         } else {
859                 return boost::shared_ptr<MasterDeviceNames>();
860         }
861 }
862
863 void
864 MidiTimeAxisView::build_controller_menu ()
865 {
866         using namespace Menu_Helpers;
867
868         if (controller_menu) {
869                 /* it exists and has not been invalidated by a channel mode change */
870                 return;
871         }
872
873         controller_menu = new Menu; // explicitly managed by us
874         MenuList& items (controller_menu->items());
875
876         /* create several "top level" menu items for sets of controllers (16 at a
877            time), and populate each one with a submenu for each controller+channel
878            combination covering the currently selected channels for this track
879         */
880
881         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
882
883         /* count the number of selected channels because we will build a different menu
884            structure if there is more than 1 selected.
885         */
886
887         int chn_cnt = 0;
888         for (uint8_t chn = 0; chn < 16; chn++) {
889                 if (selected_channels & (0x0001 << chn)) {
890                         if (++chn_cnt > 1) {
891                                 break;
892                         }
893                 }
894         }
895
896         using namespace MIDI::Name;
897         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
898
899         if (device_names && !device_names->controls().empty()) {
900                 /* Controllers names available in midnam file, generate fancy menu */
901                 unsigned n_items  = 0;
902                 unsigned n_groups = 0;
903
904                 /* TODO: This is not correct, should look up the currently applicable ControlNameList
905                    and only build a menu for that one. */
906                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
907                      l != device_names->controls().end(); ++l) {
908                         boost::shared_ptr<ControlNameList> name_list = l->second;
909                         Menu*                              ctl_menu  = NULL;
910                         
911                         for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
912                              c != name_list->controls().end();) {
913                                 const uint16_t ctl = c->second->number();
914                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
915                                         /* Skip bank select controllers since they're handled specially */
916                                         if (n_items == 0) {
917                                                 /* Create a new submenu */
918                                                 ctl_menu = manage (new Menu);
919                                         }
920                                 
921                                         MenuList& ctl_items (ctl_menu->items());
922                                         if (chn_cnt > 1) {
923                                                 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
924                                         } else {
925                                                 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
926                                         }
927                                 }
928
929                                 ++c;
930                                 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
931                                         /* Submenu has 16 items or we're done, add it to controller menu and reset */
932                                         items.push_back(
933                                                 MenuElem(string_compose(_("Controllers %1-%2"),
934                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
935                                                          *ctl_menu));
936                                         ctl_menu = NULL;
937                                         n_items  = 0;
938                                         ++n_groups;
939                                 }
940                         }
941                 }
942         } else {
943                 /* No controllers names, generate generic numeric menu */
944                 for (int i = 0; i < 127; i += 16) {
945                         Menu*     ctl_menu = manage (new Menu);
946                         MenuList& ctl_items (ctl_menu->items());
947
948                         for (int ctl = i; ctl < i+16; ++ctl) {
949                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
950                                         /* Skip bank select controllers since they're handled specially */
951                                         continue;
952                                 }
953
954                                 if (chn_cnt > 1) {
955                                         add_multi_channel_controller_item(
956                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
957                                 } else {
958                                         add_single_channel_controller_item(
959                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
960                                 }
961                         }
962
963                         /* Add submenu for this block of controllers to controller menu */
964                         items.push_back (
965                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
966                                           *ctl_menu));
967                 }
968         }
969 }
970
971 Gtk::Menu*
972 MidiTimeAxisView::build_note_mode_menu()
973 {
974         using namespace Menu_Helpers;
975
976         Menu* mode_menu = manage (new Menu);
977         MenuList& items = mode_menu->items();
978         mode_menu->set_name ("ArdourContextMenu");
979
980         RadioMenuItem::Group mode_group;
981         items.push_back (
982                 RadioMenuElem (mode_group,_("Sustained"),
983                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
984                                            Sustained, true)));
985         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
986         _note_mode_item->set_active(_note_mode == Sustained);
987
988         items.push_back (
989                 RadioMenuElem (mode_group, _("Percussive"),
990                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
991                                            Percussive, true)));
992         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
993         _percussion_mode_item->set_active(_note_mode == Percussive);
994
995         return mode_menu;
996 }
997
998 Gtk::Menu*
999 MidiTimeAxisView::build_color_mode_menu()
1000 {
1001         using namespace Menu_Helpers;
1002
1003         Menu* mode_menu = manage (new Menu);
1004         MenuList& items = mode_menu->items();
1005         mode_menu->set_name ("ArdourContextMenu");
1006
1007         RadioMenuItem::Group mode_group;
1008         items.push_back (
1009                 RadioMenuElem (mode_group, _("Meter Colors"),
1010                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1011                                            MeterColors, false, true, true)));
1012         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1013         _meter_color_mode_item->set_active(_color_mode == MeterColors);
1014
1015         items.push_back (
1016                 RadioMenuElem (mode_group, _("Channel Colors"),
1017                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1018                                            ChannelColors, false, true, true)));
1019         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1020         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1021
1022         items.push_back (
1023                 RadioMenuElem (mode_group, _("Track Color"),
1024                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1025                                            TrackColor, false, true, true)));
1026         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1027         _channel_color_mode_item->set_active(_color_mode == TrackColor);
1028
1029         return mode_menu;
1030 }
1031
1032 void
1033 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1034 {
1035         if (apply_to_selection) {
1036                 _editor.get_selection().tracks.foreach_midi_time_axis (
1037                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1038         } else {
1039                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1040                         _note_mode = mode;
1041                         midi_track()->set_note_mode(mode);
1042                         set_gui_property ("note-mode", enum_2_string(_note_mode));
1043                         _view->redisplay_track();
1044                 }
1045         }
1046 }
1047
1048 void
1049 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1050 {
1051         if (apply_to_selection) {
1052                 _editor.get_selection().tracks.foreach_midi_time_axis (
1053                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1054         } else {
1055                 if (_color_mode == mode && !force) {
1056                         return;
1057                 }
1058                 
1059                 if (_channel_selector) {
1060                         if (mode == ChannelColors) {
1061                                 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1062                         } else {
1063                                 _channel_selector->set_default_channel_color();
1064                         }
1065                 }
1066                 
1067                 _color_mode = mode;
1068                 set_gui_property ("color-mode", enum_2_string(_color_mode));
1069                 if (redisplay) {
1070                         _view->redisplay_track();
1071                 }
1072         }
1073 }
1074
1075 void
1076 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1077 {
1078         if (apply_to_selection) {
1079                 _editor.get_selection().tracks.foreach_midi_time_axis (
1080                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1081         } else {
1082                 if (!_ignore_signals) {
1083                         midi_view()->set_note_range(range);
1084                 }
1085         }
1086 }
1087
1088 void
1089 MidiTimeAxisView::update_range()
1090 {
1091         MidiGhostRegion* mgr;
1092
1093         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1094                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1095                         mgr->update_range();
1096                 }
1097         }
1098 }
1099
1100 void
1101 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1102 {
1103         using namespace MIDI::Name;
1104
1105         if (apply_to_selection) {
1106                 _editor.get_selection().tracks.foreach_midi_time_axis (
1107                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1108         } else {
1109                 if (midi_track()) {
1110                         // Show existing automation
1111                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1112
1113                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1114                                 create_automation_child(*i, true);
1115                         }
1116
1117                         // Show automation for all controllers named in midnam file
1118                         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1119                         if (gui_property (X_("midnam-model-name")) != "Generic" &&
1120                              device_names && !device_names->controls().empty()) {
1121                                 const std::string device_mode       = _midnam_custom_device_mode_selector.get_active_text();
1122                                 const uint16_t    selected_channels = midi_track()->get_playback_channel_mask();
1123                                 for (uint32_t chn = 0; chn < 16; ++chn) {
1124                                         if ((selected_channels & (0x0001 << chn)) == 0) {
1125                                                 // Channel not in use
1126                                                 continue;
1127                                         }
1128
1129                                         boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1130                                                 device_mode, chn);
1131                                         if (!chan_names) {
1132                                                 continue;
1133                                         }
1134
1135                                         boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1136                                                 chan_names->control_list_name());
1137                                         if (!control_names) {
1138                                                 continue;
1139                                         }
1140
1141                                         for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1142                                              c != control_names->controls().end();
1143                                              ++c) {
1144                                                 const uint16_t ctl = c->second->number();
1145                                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1146                                                         /* Skip bank select controllers since they're handled specially */
1147                                                         const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1148                                                         create_automation_child(param, true);
1149                                                 }
1150                                         }
1151                                 }
1152                         }
1153                 }
1154
1155                 RouteTimeAxisView::show_all_automation ();
1156         }
1157 }
1158
1159 void
1160 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1161 {
1162         if (apply_to_selection) {
1163                 _editor.get_selection().tracks.foreach_midi_time_axis (
1164                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1165         } else {
1166                 if (midi_track()) {
1167                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1168
1169                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1170                                 create_automation_child (*i, true);
1171                         }
1172                 }
1173
1174                 RouteTimeAxisView::show_existing_automation ();
1175         }
1176 }
1177
1178 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1179  */
1180 void
1181 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1182 {
1183         if (param.type() == NullAutomation) {
1184                 return;
1185         }
1186
1187         AutomationTracks::iterator existing = _automation_tracks.find (param);
1188
1189         if (existing != _automation_tracks.end()) {
1190
1191                 /* automation track created because we had existing data for
1192                  * the processor, but visibility may need to be controlled
1193                  * since it will have been set visible by default.
1194                  */
1195
1196                 existing->second->set_marked_for_display (show);
1197
1198                 if (!no_redraw) {
1199                         request_redraw ();
1200                 }
1201
1202                 return;
1203         }
1204
1205         boost::shared_ptr<AutomationTimeAxisView> track;
1206         boost::shared_ptr<AutomationControl> control;
1207
1208
1209         switch (param.type()) {
1210
1211         case GainAutomation:
1212                 create_gain_automation_child (param, show);
1213                 break;
1214
1215         case MuteAutomation:
1216                 create_mute_automation_child (param, show);
1217                 break;
1218
1219         case PluginAutomation:
1220                 /* handled elsewhere */
1221                 break;
1222
1223         case MidiCCAutomation:
1224         case MidiPgmChangeAutomation:
1225         case MidiPitchBenderAutomation:
1226         case MidiChannelPressureAutomation:
1227         case MidiSystemExclusiveAutomation:
1228                 /* These controllers are region "automation" - they are owned
1229                  * by regions (and their MidiModels), not by the track. As a
1230                  * result there is no AutomationList/Line for the track, but we create
1231                  * a controller for the user to write immediate events, so the editor
1232                  * can act as a control surface for the present MIDI controllers.
1233                  *
1234                  * TODO: Record manipulation of the controller to regions?
1235                  */
1236
1237                 control = _route->automation_control(param, true);
1238                 track.reset (new AutomationTimeAxisView (
1239                                      _session,
1240                                      _route,
1241                                      control ? _route : boost::shared_ptr<Automatable> (),
1242                                      control,
1243                                      param,
1244                                      _editor,
1245                                      *this,
1246                                      true,
1247                                      parent_canvas,
1248                                      _route->describe_parameter(param)));
1249
1250                 if (_view) {
1251                         _view->foreach_regionview (
1252                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1253                 }
1254
1255                 add_automation_child (param, track, show);
1256                 break;
1257
1258         case PanWidthAutomation:
1259         case PanElevationAutomation:
1260         case PanAzimuthAutomation:
1261                 ensure_pan_views (show);
1262                 break;
1263
1264         default:
1265                 error << "MidiTimeAxisView: unknown automation child "
1266                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1267         }
1268 }
1269
1270 void
1271 MidiTimeAxisView::route_active_changed ()
1272 {
1273         RouteUI::route_active_changed ();
1274
1275         if (is_track()) {
1276                 if (_route->active()) {
1277                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1278                         time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1279                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1280                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1281                 } else {
1282                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1283                         time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1284                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1285                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1286                 }
1287         } else {
1288                 if (_route->active()) {
1289                         controls_ebox.set_name ("BusControlsBaseUnselected");
1290                         time_axis_frame.set_name ("BusControlsBaseUnselected");
1291                         controls_base_selected_name = "BusControlsBaseSelected";
1292                         controls_base_unselected_name = "BusControlsBaseUnselected";
1293                 } else {
1294                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1295                         time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1296                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1297                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1298                 }
1299         }
1300 }
1301
1302 void
1303 MidiTimeAxisView::set_note_selection (uint8_t note)
1304 {
1305         if (!_editor.internal_editing()) {
1306                 return;
1307         }
1308
1309         uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1310
1311         if (_view->num_selected_regionviews() == 0) {
1312                 _view->foreach_regionview (
1313                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1314                                     note, chn_mask));
1315         } else {
1316                 _view->foreach_selected_regionview (
1317                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1318                                     note, chn_mask));
1319         }
1320 }
1321
1322 void
1323 MidiTimeAxisView::add_note_selection (uint8_t note)
1324 {
1325         if (!_editor.internal_editing()) {
1326                 return;
1327         }
1328
1329         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1330
1331         if (_view->num_selected_regionviews() == 0) {
1332                 _view->foreach_regionview (
1333                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1334                                     note, chn_mask));
1335         } else {
1336                 _view->foreach_selected_regionview (
1337                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1338                                     note, chn_mask));
1339         }
1340 }
1341
1342 void
1343 MidiTimeAxisView::extend_note_selection (uint8_t note)
1344 {
1345         if (!_editor.internal_editing()) {
1346                 return;
1347         }
1348
1349         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1350
1351         if (_view->num_selected_regionviews() == 0) {
1352                 _view->foreach_regionview (
1353                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1354                                     note, chn_mask));
1355         } else {
1356                 _view->foreach_selected_regionview (
1357                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1358                                     note, chn_mask));
1359         }
1360 }
1361
1362 void
1363 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1364 {
1365         if (!_editor.internal_editing()) {
1366                 return;
1367         }
1368
1369         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1370
1371         if (_view->num_selected_regionviews() == 0) {
1372                 _view->foreach_regionview (
1373                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1374                                     note, chn_mask));
1375         } else {
1376                 _view->foreach_selected_regionview (
1377                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1378                                     note, chn_mask));
1379         }
1380 }
1381
1382 void
1383 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1384 {
1385         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1386 }
1387
1388 void
1389 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1390 {
1391         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1392 }
1393
1394 void
1395 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1396 {
1397         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1398 }
1399
1400 void
1401 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1402 {
1403         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1404 }
1405
1406 void
1407 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1408 {
1409         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1410            the right ones.
1411         */
1412
1413         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1414         bool changed = false;
1415
1416         no_redraw = true;
1417
1418         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1419
1420                 for (uint32_t chn = 0; chn < 16; ++chn) {
1421                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1422                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1423
1424                         if (!track) {
1425                                 continue;
1426                         }
1427
1428                         if ((selected_channels & (0x0001 << chn)) == 0) {
1429                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1430                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1431                                 */
1432                                 changed = track->set_marked_for_display (false) || changed;
1433                         } else {
1434                                 changed = track->set_marked_for_display (true) || changed;
1435                         }
1436                 }
1437         }
1438
1439         no_redraw = false;
1440
1441         /* TODO: Bender, Pressure */
1442
1443         /* invalidate the controller menu, so that we rebuild it next time */
1444         _controller_menu_map.clear ();
1445         delete controller_menu;
1446         controller_menu = 0;
1447
1448         if (changed) {
1449                 request_redraw ();
1450         }
1451 }
1452
1453 Gtk::CheckMenuItem*
1454 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1455 {
1456         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1457         if (m) {
1458                 return m;
1459         }
1460
1461         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1462         if (i != _controller_menu_map.end()) {
1463                 return i->second;
1464         }
1465
1466         i = _channel_command_menu_map.find (param);
1467         if (i != _channel_command_menu_map.end()) {
1468                 return i->second;
1469         }
1470
1471         return 0;
1472 }
1473
1474 boost::shared_ptr<MidiRegion>
1475 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1476 {
1477         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1478
1479         real_editor->begin_reversible_command (Operations::create_region);
1480         playlist()->clear_changes ();
1481
1482         real_editor->snap_to (pos, RoundNearest);
1483
1484         boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1485         PropertyList plist;
1486
1487         plist.add (ARDOUR::Properties::start, 0);
1488         plist.add (ARDOUR::Properties::length, length);
1489         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1490
1491         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1492
1493         playlist()->add_region (region, pos);
1494         _session->add_command (new StatefulDiffCommand (playlist()));
1495
1496         if (commit) {
1497                 real_editor->commit_reversible_command ();
1498         }
1499
1500         return boost::dynamic_pointer_cast<MidiRegion>(region);
1501 }
1502
1503 void
1504 MidiTimeAxisView::ensure_step_editor ()
1505 {
1506         if (!_step_editor) {
1507                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1508         }
1509 }
1510
1511 void
1512 MidiTimeAxisView::start_step_editing ()
1513 {
1514         ensure_step_editor ();
1515         _step_editor->start_step_editing ();
1516
1517 }
1518 void
1519 MidiTimeAxisView::stop_step_editing ()
1520 {
1521         if (_step_editor) {
1522                 _step_editor->stop_step_editing ();
1523         }
1524 }
1525
1526 /** @return channel (counted from 0) to add an event to, based on the current setting
1527  *  of the channel selector.
1528  */
1529 uint8_t
1530 MidiTimeAxisView::get_channel_for_add () const
1531 {
1532         uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1533         int chn_cnt = 0;
1534         uint8_t channel = 0;
1535
1536         /* pick the highest selected channel, unless all channels are selected,
1537            which is interpreted to mean channel 1 (zero)
1538         */
1539
1540         for (uint16_t i = 0; i < 16; ++i) {
1541                 if (chn_mask & (1<<i)) {
1542                         channel = i;
1543                         chn_cnt++;
1544                 }
1545         }
1546
1547         if (chn_cnt == 16) {
1548                 channel = 0;
1549         }
1550
1551         return channel;
1552 }
1553
1554 void
1555 MidiTimeAxisView::note_range_changed ()
1556 {
1557         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1558         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1559 }
1560
1561 void
1562 MidiTimeAxisView::contents_height_changed ()
1563 {
1564         _range_scroomer->queue_resize ();
1565 }
1566
1567 void
1568 MidiTimeAxisView::playback_channel_mode_changed ()
1569 {
1570         switch (midi_track()->get_playback_channel_mode()) {
1571         case AllChannels:
1572                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1573                 break;
1574         case FilterChannels:
1575                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1576                 break;
1577         case ForceChannel:
1578                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1579                 break;
1580         }
1581 }
1582
1583 void
1584 MidiTimeAxisView::capture_channel_mode_changed ()
1585 {
1586         switch (midi_track()->get_capture_channel_mode()) {
1587         case AllChannels:
1588                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1589                 break;
1590         case FilterChannels:
1591                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1592                 break;
1593         case ForceChannel:
1594                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1595                 break;
1596         }
1597 }