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