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