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