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