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