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