Fix visibility of MIDI controller automation tracks across saves.
[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 (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);
605         } else {
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);
609         }
610
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"))));
616
617         _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
618
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"))));
624
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;
628                 }
629         }
630
631 }
632
633 void
634 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
635 {
636         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
637
638         for (uint8_t chn = 0; chn < 16; chn++) {
639                 if (selected_channels & (0x0001 << chn)) {
640
641                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
642                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
643
644                         if (menu) {
645                                 menu->set_active (yn);
646                         }
647                 }
648         }
649 }
650
651 void
652 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
653                                                  const string&           label,
654                                                  AutomationType          auto_type,
655                                                  uint8_t                 cmd)
656 {
657         using namespace Menu_Helpers;
658
659         /* count the number of selected channels because we will build a different menu
660            structure if there is more than 1 selected.
661          */
662
663         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
664         int chn_cnt = 0;
665
666         for (uint8_t chn = 0; chn < 16; chn++) {
667                 if (selected_channels & (0x0001 << chn)) {
668                         if (++chn_cnt > 1) {
669                                 break;
670                         }
671                 }
672         }
673
674         if (chn_cnt > 1) {
675
676                 /* multiple channels - create a submenu, with 1 item per channel */
677
678                 Menu* chn_menu = manage (new Menu);
679                 MenuList& chn_items (chn_menu->items());
680                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
681
682                 /* add a couple of items to hide/show all of them */
683
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)));
692
693                 for (uint8_t chn = 0; chn < 16; chn++) {
694                         if (selected_channels & (0x0001 << chn)) {
695
696                                 /* for each selected channel, add a menu item for this controller */
697
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)));
703
704                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
705                                 bool visible = false;
706
707                                 if (track) {
708                                         if (track->marked_for_display()) {
709                                                 visible = true;
710                                         }
711                                 }
712
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);
716                         }
717                 }
718
719                 /* now create an item in the parent menu that has the per-channel list as a submenu */
720
721                 items.push_back (MenuElem (label, *chn_menu));
722
723         } else {
724
725                 /* just one channel - create a single menu item for this command+channel combination*/
726
727                 for (uint8_t chn = 0; chn < 16; chn++) {
728                         if (selected_channels & (0x0001 << chn)) {
729
730                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
731                                 items.push_back (
732                                         CheckMenuElem (label,
733                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
734                                                                    fully_qualified_param)));
735
736                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
737                                 bool visible = false;
738
739                                 if (track) {
740                                         if (track->marked_for_display()) {
741                                                 visible = true;
742                                         }
743                                 }
744
745                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
746                                 _channel_command_menu_map[fully_qualified_param] = cmi;
747                                 cmi->set_active (visible);
748
749                                 /* one channel only */
750                                 break;
751                         }
752                 }
753         }
754 }
755
756 /** Add a single menu item for a controller on one channel. */
757 void
758 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
759                                                      int                     ctl,
760                                                      const std::string&      name)
761 {
762         using namespace Menu_Helpers;
763
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)) {
767
768                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
769                         ctl_items.push_back (
770                                 CheckMenuElem (
771                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
772                                         sigc::bind (
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);
776
777                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
778                                 fully_qualified_param);
779
780                         bool visible = false;
781                         if (track) {
782                                 if (track->marked_for_display()) {
783                                         visible = true;
784                                 }
785                         }
786
787                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
788                         _controller_menu_map[fully_qualified_param] = cmi;
789                         cmi->set_active (visible);
790
791                         /* one channel only */
792                         break;
793                 }
794         }
795 }
796
797 /** Add a submenu with 1 item per channel for a controller on many channels. */
798 void
799 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
800                                                     int                     ctl,
801                                                     const std::string&      name)
802 {
803         using namespace Menu_Helpers;
804
805         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
806
807         Menu* chn_menu = manage (new Menu);
808         MenuList& chn_items (chn_menu->items());
809
810         /* add a couple of items to hide/show this controller on all channels */
811
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)));
821
822         for (uint8_t chn = 0; chn < 16; chn++) {
823                 if (selected_channels & (0x0001 << chn)) {
824
825                         /* for each selected channel, add a menu item for this controller */
826
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)));
832
833                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
834                                 fully_qualified_param);
835                         bool visible = false;
836
837                         if (track) {
838                                 if (track->marked_for_display()) {
839                                         visible = true;
840                                 }
841                         }
842
843                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
844                         _controller_menu_map[fully_qualified_param] = cmi;
845                         cmi->set_active (visible);
846                 }
847         }
848
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),
851                                        *chn_menu));
852         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
853 }
854
855 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
856 MidiTimeAxisView::get_device_mode()
857 {
858         using namespace MIDI::Name;
859
860         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
861         if (!device_names) {
862                 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
863         }
864
865         return device_names->custom_device_mode_by_name(
866                 gui_property (X_("midnam-custom-device-mode")));
867 }
868
869 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
870 MidiTimeAxisView::get_device_names()
871 {
872         using namespace MIDI::Name;
873
874         const std::string model = gui_property (X_("midnam-model-name"));
875
876         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
877                 .document_by_model(model);
878         if (midnam) {
879                 return midnam->master_device_names(model);
880         } else {
881                 return boost::shared_ptr<MasterDeviceNames>();
882         }
883 }
884
885 void
886 MidiTimeAxisView::build_controller_menu ()
887 {
888         using namespace Menu_Helpers;
889
890         if (controller_menu) {
891                 /* it exists and has not been invalidated by a channel mode change */
892                 return;
893         }
894
895         controller_menu = new Menu; // explicitly managed by us
896         MenuList& items (controller_menu->items());
897
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
901         */
902
903         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
904
905         /* count the number of selected channels because we will build a different menu
906            structure if there is more than 1 selected.
907         */
908
909         int chn_cnt = 0;
910         for (uint8_t chn = 0; chn < 16; chn++) {
911                 if (selected_channels & (0x0001 << chn)) {
912                         if (++chn_cnt > 1) {
913                                 break;
914                         }
915                 }
916         }
917
918         using namespace MIDI::Name;
919         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
920
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;
925
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;
932                         
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 */
938                                         if (n_items == 0) {
939                                                 /* Create a new submenu */
940                                                 ctl_menu = manage (new Menu);
941                                         }
942                                 
943                                         MenuList& ctl_items (ctl_menu->items());
944                                         if (chn_cnt > 1) {
945                                                 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
946                                         } else {
947                                                 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
948                                         }
949                                 }
950
951                                 ++c;
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 */
954                                         items.push_back(
955                                                 MenuElem(string_compose(_("Controllers %1-%2"),
956                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
957                                                          *ctl_menu));
958                                         ctl_menu = NULL;
959                                         n_items  = 0;
960                                         ++n_groups;
961                                 }
962                         }
963                 }
964         } else {
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());
969
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 */
973                                         continue;
974                                 }
975
976                                 if (chn_cnt > 1) {
977                                         add_multi_channel_controller_item(
978                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
979                                 } else {
980                                         add_single_channel_controller_item(
981                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
982                                 }
983                         }
984
985                         /* Add submenu for this block of controllers to controller menu */
986                         items.push_back (
987                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
988                                           *ctl_menu));
989                 }
990         }
991 }
992
993 Gtk::Menu*
994 MidiTimeAxisView::build_note_mode_menu()
995 {
996         using namespace Menu_Helpers;
997
998         Menu* mode_menu = manage (new Menu);
999         MenuList& items = mode_menu->items();
1000         mode_menu->set_name ("ArdourContextMenu");
1001
1002         RadioMenuItem::Group mode_group;
1003         items.push_back (
1004                 RadioMenuElem (mode_group,_("Sustained"),
1005                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1006                                            Sustained, true)));
1007         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1008         _note_mode_item->set_active(_note_mode == Sustained);
1009
1010         items.push_back (
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);
1016
1017         return mode_menu;
1018 }
1019
1020 Gtk::Menu*
1021 MidiTimeAxisView::build_color_mode_menu()
1022 {
1023         using namespace Menu_Helpers;
1024
1025         Menu* mode_menu = manage (new Menu);
1026         MenuList& items = mode_menu->items();
1027         mode_menu->set_name ("ArdourContextMenu");
1028
1029         RadioMenuItem::Group mode_group;
1030         items.push_back (
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);
1036
1037         items.push_back (
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);
1043
1044         items.push_back (
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);
1050
1051         return mode_menu;
1052 }
1053
1054 void
1055 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1056 {
1057         if (apply_to_selection) {
1058                 _editor.get_selection().tracks.foreach_midi_time_axis (
1059                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1060         } else {
1061                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1062                         _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();
1066                 }
1067         }
1068 }
1069
1070 void
1071 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1072 {
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));
1076         } else {
1077                 if (_color_mode == mode && !force) {
1078                         return;
1079                 }
1080                 
1081                 if (_channel_selector) {
1082                         if (mode == ChannelColors) {
1083                                 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1084                         } else {
1085                                 _channel_selector->set_default_channel_color();
1086                         }
1087                 }
1088                 
1089                 _color_mode = mode;
1090                 set_gui_property ("color-mode", enum_2_string(_color_mode));
1091                 if (redisplay) {
1092                         _view->redisplay_track();
1093                 }
1094         }
1095 }
1096
1097 void
1098 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1099 {
1100         if (apply_to_selection) {
1101                 _editor.get_selection().tracks.foreach_midi_time_axis (
1102                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1103         } else {
1104                 if (!_ignore_signals) {
1105                         midi_view()->set_note_range(range);
1106                 }
1107         }
1108 }
1109
1110 void
1111 MidiTimeAxisView::update_range()
1112 {
1113         MidiGhostRegion* mgr;
1114
1115         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1116                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1117                         mgr->update_range();
1118                 }
1119         }
1120 }
1121
1122 void
1123 MidiTimeAxisView::ensure_pan_views (bool show)
1124 {
1125         bool changed = false;
1126         for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1127                 changed = true;
1128                 (*i)->set_marked_for_display (false);
1129         }
1130         if (changed) {
1131                 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1132         }
1133         pan_tracks.clear();
1134
1135         if (!_route->panner()) {
1136                 return;
1137         }
1138
1139         set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1140         set<Evoral::Parameter>::iterator p;
1141
1142         for (p = params.begin(); p != params.end(); ++p) {
1143                 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1144
1145                 if (pan_control->parameter().type() == NullAutomation) {
1146                         error << "Pan control has NULL automation type!" << endmsg;
1147                         continue;
1148                 }
1149
1150                 if (automation_child (pan_control->parameter ()).get () == 0) {
1151
1152                         /* we don't already have an AutomationTimeAxisView for this parameter */
1153
1154                         std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1155
1156                         boost::shared_ptr<AutomationTimeAxisView> t (
1157                                         new AutomationTimeAxisView (_session,
1158                                                 _route,
1159                                                 _route->pannable(),
1160                                                 pan_control,
1161                                                 pan_control->parameter (),
1162                                                 _editor,
1163                                                 *this,
1164                                                 false,
1165                                                 parent_canvas,
1166                                                 name)
1167                                         );
1168
1169                         pan_tracks.push_back (t);
1170                         add_automation_child (*p, t, show);
1171                 } else {
1172                         pan_tracks.push_back (automation_child (pan_control->parameter ()));
1173                 }
1174         }
1175 }
1176
1177 void
1178 MidiTimeAxisView::update_gain_track_visibility ()
1179 {
1180         bool const showit = gain_automation_item->get_active();
1181
1182         if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1183                 gain_track->set_marked_for_display (showit);
1184
1185                 /* now trigger a redisplay */
1186
1187                 if (!no_redraw) {
1188                          _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1189                 }
1190         }
1191 }
1192
1193 void
1194 MidiTimeAxisView::update_pan_track_visibility ()
1195 {
1196         bool const showit = pan_automation_item->get_active();
1197         bool changed = false;
1198
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)) {
1201                         changed = true;
1202                 }
1203         }
1204
1205         if (changed) {
1206                 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1207         }
1208 }
1209
1210 void
1211 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1212 {
1213         using namespace MIDI::Name;
1214
1215         if (apply_to_selection) {
1216                 _editor.get_selection().tracks.foreach_midi_time_axis (
1217                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1218         } else {
1219                 if (midi_track()) {
1220                         // Show existing automation
1221                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1222
1223                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1224                                 create_automation_child(*i, true);
1225                         }
1226
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
1236                                                 continue;
1237                                         }
1238
1239                                         boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1240                                                 device_mode, chn);
1241                                         if (!chan_names) {
1242                                                 continue;
1243                                         }
1244
1245                                         boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1246                                                 chan_names->control_list_name());
1247                                         if (!control_names) {
1248                                                 continue;
1249                                         }
1250
1251                                         for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1252                                              c != control_names->controls().end();
1253                                              ++c) {
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);
1259                                                 }
1260                                         }
1261                                 }
1262                         }
1263                 }
1264
1265                 RouteTimeAxisView::show_all_automation ();
1266         }
1267 }
1268
1269 void
1270 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1271 {
1272         if (apply_to_selection) {
1273                 _editor.get_selection().tracks.foreach_midi_time_axis (
1274                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1275         } else {
1276                 if (midi_track()) {
1277                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1278
1279                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1280                                 create_automation_child (*i, true);
1281                         }
1282                 }
1283
1284                 RouteTimeAxisView::show_existing_automation ();
1285         }
1286 }
1287
1288 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1289  */
1290 void
1291 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1292 {
1293         if (param.type() == NullAutomation) {
1294                 return;
1295         }
1296
1297         AutomationTracks::iterator existing = _automation_tracks.find (param);
1298
1299         if (existing != _automation_tracks.end()) {
1300
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.
1304                  */
1305
1306                 existing->second->set_marked_for_display (show);
1307
1308                 if (!no_redraw) {
1309                         request_redraw ();
1310                 }
1311
1312                 return;
1313         }
1314
1315         boost::shared_ptr<AutomationTimeAxisView> track;
1316         boost::shared_ptr<AutomationControl> control;
1317
1318
1319         switch (param.type()) {
1320
1321         case GainAutomation:
1322                 create_gain_automation_child (param, show);
1323                 break;
1324
1325         case MuteAutomation:
1326                 create_mute_automation_child (param, show);
1327                 break;
1328
1329         case PluginAutomation:
1330                 /* handled elsewhere */
1331                 break;
1332
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.
1343                  *
1344                  * TODO: Record manipulation of the controller to regions?
1345                  */
1346
1347                 control = _route->automation_control(param, true);
1348                 track.reset (new AutomationTimeAxisView (
1349                                      _session,
1350                                      _route,
1351                                      control ? _route : boost::shared_ptr<Automatable> (),
1352                                      control,
1353                                      param,
1354                                      _editor,
1355                                      *this,
1356                                      true,
1357                                      parent_canvas,
1358                                      _route->describe_parameter(param)));
1359
1360                 if (_view) {
1361                         _view->foreach_regionview (
1362                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1363                 }
1364
1365                 add_automation_child (param, track, show);
1366                 break;
1367
1368         case PanWidthAutomation:
1369         case PanElevationAutomation:
1370         case PanAzimuthAutomation:
1371                 ensure_pan_views (show);
1372                 break;
1373
1374         default:
1375                 error << "MidiTimeAxisView: unknown automation child "
1376                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1377         }
1378 }
1379
1380 void
1381 MidiTimeAxisView::route_active_changed ()
1382 {
1383         RouteUI::route_active_changed ();
1384
1385         if (is_track()) {
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";
1391                 } else {
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";
1396                 }
1397         } else {
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";
1403                 } else {
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";
1408                 }
1409         }
1410 }
1411
1412 void
1413 MidiTimeAxisView::set_note_selection (uint8_t note)
1414 {
1415         if (!_editor.internal_editing()) {
1416                 return;
1417         }
1418
1419         uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1420
1421         if (_view->num_selected_regionviews() == 0) {
1422                 _view->foreach_regionview (
1423                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1424                                     note, chn_mask));
1425         } else {
1426                 _view->foreach_selected_regionview (
1427                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1428                                     note, chn_mask));
1429         }
1430 }
1431
1432 void
1433 MidiTimeAxisView::add_note_selection (uint8_t note)
1434 {
1435         if (!_editor.internal_editing()) {
1436                 return;
1437         }
1438
1439         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1440
1441         if (_view->num_selected_regionviews() == 0) {
1442                 _view->foreach_regionview (
1443                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1444                                     note, chn_mask));
1445         } else {
1446                 _view->foreach_selected_regionview (
1447                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1448                                     note, chn_mask));
1449         }
1450 }
1451
1452 void
1453 MidiTimeAxisView::extend_note_selection (uint8_t note)
1454 {
1455         if (!_editor.internal_editing()) {
1456                 return;
1457         }
1458
1459         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1460
1461         if (_view->num_selected_regionviews() == 0) {
1462                 _view->foreach_regionview (
1463                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1464                                     note, chn_mask));
1465         } else {
1466                 _view->foreach_selected_regionview (
1467                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1468                                     note, chn_mask));
1469         }
1470 }
1471
1472 void
1473 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1474 {
1475         if (!_editor.internal_editing()) {
1476                 return;
1477         }
1478
1479         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1480
1481         if (_view->num_selected_regionviews() == 0) {
1482                 _view->foreach_regionview (
1483                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1484                                     note, chn_mask));
1485         } else {
1486                 _view->foreach_selected_regionview (
1487                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1488                                     note, chn_mask));
1489         }
1490 }
1491
1492 void
1493 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1494 {
1495         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1496 }
1497
1498 void
1499 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1500 {
1501         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1502 }
1503
1504 void
1505 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1506 {
1507         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1508 }
1509
1510 void
1511 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1512 {
1513         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1514 }
1515
1516 void
1517 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1518 {
1519         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1520            the right ones.
1521         */
1522
1523         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1524         bool changed = false;
1525
1526         no_redraw = true;
1527
1528         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1529
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);
1533
1534                         if (!track) {
1535                                 continue;
1536                         }
1537
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.
1541                                 */
1542                                 changed = track->set_marked_for_display (false) || changed;
1543                         } else {
1544                                 changed = track->set_marked_for_display (true) || changed;
1545                         }
1546                 }
1547         }
1548
1549         no_redraw = false;
1550
1551         /* TODO: Bender, Pressure */
1552
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;
1557
1558         if (changed) {
1559                 request_redraw ();
1560         }
1561 }
1562
1563 Gtk::CheckMenuItem*
1564 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1565 {
1566         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1567         if (m) {
1568                 return m;
1569         }
1570
1571         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1572         if (i != _controller_menu_map.end()) {
1573                 return i->second;
1574         }
1575
1576         i = _channel_command_menu_map.find (param);
1577         if (i != _channel_command_menu_map.end()) {
1578                 return i->second;
1579         }
1580
1581         return 0;
1582 }
1583
1584 boost::shared_ptr<MidiRegion>
1585 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1586 {
1587         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1588
1589         real_editor->begin_reversible_command (Operations::create_region);
1590         playlist()->clear_changes ();
1591
1592         real_editor->snap_to (pos, RoundNearest);
1593
1594         boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1595         PropertyList plist;
1596
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()));
1600
1601         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1602
1603         playlist()->add_region (region, pos);
1604         _session->add_command (new StatefulDiffCommand (playlist()));
1605
1606         if (commit) {
1607                 real_editor->commit_reversible_command ();
1608         }
1609
1610         return boost::dynamic_pointer_cast<MidiRegion>(region);
1611 }
1612
1613 void
1614 MidiTimeAxisView::ensure_step_editor ()
1615 {
1616         if (!_step_editor) {
1617                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1618         }
1619 }
1620
1621 void
1622 MidiTimeAxisView::start_step_editing ()
1623 {
1624         ensure_step_editor ();
1625         _step_editor->start_step_editing ();
1626
1627 }
1628 void
1629 MidiTimeAxisView::stop_step_editing ()
1630 {
1631         if (_step_editor) {
1632                 _step_editor->stop_step_editing ();
1633         }
1634 }
1635
1636 /** @return channel (counted from 0) to add an event to, based on the current setting
1637  *  of the channel selector.
1638  */
1639 uint8_t
1640 MidiTimeAxisView::get_channel_for_add () const
1641 {
1642         uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1643         int chn_cnt = 0;
1644         uint8_t channel = 0;
1645
1646         /* pick the highest selected channel, unless all channels are selected,
1647            which is interpreted to mean channel 1 (zero)
1648         */
1649
1650         for (uint16_t i = 0; i < 16; ++i) {
1651                 if (chn_mask & (1<<i)) {
1652                         channel = i;
1653                         chn_cnt++;
1654                 }
1655         }
1656
1657         if (chn_cnt == 16) {
1658                 channel = 0;
1659         }
1660
1661         return channel;
1662 }
1663
1664 void
1665 MidiTimeAxisView::note_range_changed ()
1666 {
1667         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1668         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1669 }
1670
1671 void
1672 MidiTimeAxisView::contents_height_changed ()
1673 {
1674         _range_scroomer->queue_resize ();
1675 }
1676
1677 void
1678 MidiTimeAxisView::playback_channel_mode_changed ()
1679 {
1680         switch (midi_track()->get_playback_channel_mode()) {
1681         case AllChannels:
1682                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1683                 break;
1684         case FilterChannels:
1685                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1686                 break;
1687         case ForceChannel:
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())));
1689                 break;
1690         }
1691 }
1692
1693 void
1694 MidiTimeAxisView::capture_channel_mode_changed ()
1695 {
1696         switch (midi_track()->get_capture_channel_mode()) {
1697         case AllChannels:
1698                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1699                 break;
1700         case FilterChannels:
1701                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1702                 break;
1703         case ForceChannel:
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())));
1705                 break;
1706         }
1707 }