move midi scroomer to right of meter and fix alignment
[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                 _note_mode = midi_track()->note_mode();
166         } else { // MIDI bus (which doesn't exist yet..)
167                 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
168         }
169
170         /* if set_state above didn't create a gain automation child, we need to make one */
171         if (automation_child (GainAutomation) == 0) {
172                 create_automation_child (GainAutomation, false);
173         }
174
175         /* if set_state above didn't create a mute automation child, we need to make one */
176         if (automation_child (MuteAutomation) == 0) {
177                 create_automation_child (MuteAutomation, false);
178         }
179
180         if (_route->panner_shell()) {
181                 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
182         }
183
184         /* map current state of the route */
185         ensure_pan_views (false);
186
187         processors_changed (RouteProcessorChange ());
188
189         _route->processors_changed.connect (*this, invalidator (*this),
190                                             boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
191                                             gui_context());
192
193         if (is_track()) {
194                 _piano_roll_header->SetNoteSelection.connect (
195                         sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
196                 _piano_roll_header->AddNoteSelection.connect (
197                         sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
198                 _piano_roll_header->ExtendNoteSelection.connect (
199                         sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
200                 _piano_roll_header->ToggleNoteSelection.connect (
201                         sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
202
203                 /* Suspend updates of the StreamView during scroomer drags to speed things up */
204                 _range_scroomer->DragStarting.connect (
205                         sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
206                 _range_scroomer->DragFinishing.connect (
207                         sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
208
209                 /* Put the scroomer and the keyboard in a VBox with a padding
210                    label so that they can be reduced in height for stacked-view
211                    tracks.
212                 */
213
214                 top_hbox.remove(gm.get_level_meter());
215                 VBox* v = manage (new VBox);
216                 HBox* h = manage (new HBox);
217                 h->pack_end (*_piano_roll_header);
218                 h->pack_end (*_range_scroomer);
219                 h->pack_end (gm.get_level_meter(), false, false, 4);
220                 v->pack_start (*h, false, false);
221                 v->show ();
222                 h->show ();
223                 top_hbox.pack_end(*v, false, false, 0);
224                 if (!ARDOUR::Profile->get_mixbus()) {
225                         controls_meters_size_group->remove_widget (gm.get_level_meter());
226                         controls_meters_size_group->add_widget (*h);
227                 }
228                 // make up for level_meter 4 spc padding in RTA
229                 Gtk::Fixed *blank = manage(new Gtk::Fixed());
230                 blank->set_size_request(8, -1);
231                 blank->show();
232                 top_hbox.pack_end(*blank, false, false, 0);
233
234                 controls_ebox.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
1319         switch (param.type()) {
1320
1321         case GainAutomation:
1322                 create_gain_automation_child (param, show);
1323                 break;
1324
1325         case MuteAutomation:
1326                 create_mute_automation_child (param, show);
1327                 break;
1328
1329         case PluginAutomation:
1330                 /* handled elsewhere */
1331                 break;
1332
1333         case MidiCCAutomation:
1334         case MidiPgmChangeAutomation:
1335         case MidiPitchBenderAutomation:
1336         case MidiChannelPressureAutomation:
1337         case MidiSystemExclusiveAutomation:
1338                 /* These controllers are region "automation" - they are owned
1339                  * by regions (and their MidiModels), not by the track. As a
1340                  * result we do not create an AutomationList/Line for the track
1341                  * ... except here we are doing something!! XXX 
1342                  */
1343
1344                 track.reset (new AutomationTimeAxisView (
1345                                      _session,
1346                                      _route,
1347                                      boost::shared_ptr<Automatable> (),
1348                                      boost::shared_ptr<AutomationControl> (),
1349                                      param,
1350                                      _editor,
1351                                      *this,
1352                                      true,
1353                                      parent_canvas,
1354                                      _route->describe_parameter(param)));
1355
1356                 if (_view) {
1357                         _view->foreach_regionview (
1358                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1359                 }
1360
1361                 add_automation_child (param, track, show);
1362                 break;
1363
1364         case PanWidthAutomation:
1365         case PanElevationAutomation:
1366         case PanAzimuthAutomation:
1367                 ensure_pan_views (show);
1368                 break;
1369
1370         default:
1371                 error << "MidiTimeAxisView: unknown automation child "
1372                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1373         }
1374 }
1375
1376 void
1377 MidiTimeAxisView::route_active_changed ()
1378 {
1379         RouteUI::route_active_changed ();
1380
1381         if (is_track()) {
1382                 if (_route->active()) {
1383                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1384                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1385                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1386                 } else {
1387                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1388                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1389                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1390                 }
1391         } else {
1392                 if (_route->active()) {
1393                         controls_ebox.set_name ("BusControlsBaseUnselected");
1394                         controls_base_selected_name = "BusControlsBaseSelected";
1395                         controls_base_unselected_name = "BusControlsBaseUnselected";
1396                 } else {
1397                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1398                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1399                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1400                 }
1401         }
1402 }
1403
1404 void
1405 MidiTimeAxisView::set_note_selection (uint8_t note)
1406 {
1407         if (!_editor.internal_editing()) {
1408                 return;
1409         }
1410
1411         uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1412
1413         if (_view->num_selected_regionviews() == 0) {
1414                 _view->foreach_regionview (
1415                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1416                                     note, chn_mask));
1417         } else {
1418                 _view->foreach_selected_regionview (
1419                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1420                                     note, chn_mask));
1421         }
1422 }
1423
1424 void
1425 MidiTimeAxisView::add_note_selection (uint8_t note)
1426 {
1427         if (!_editor.internal_editing()) {
1428                 return;
1429         }
1430
1431         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1432
1433         if (_view->num_selected_regionviews() == 0) {
1434                 _view->foreach_regionview (
1435                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1436                                     note, chn_mask));
1437         } else {
1438                 _view->foreach_selected_regionview (
1439                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1440                                     note, chn_mask));
1441         }
1442 }
1443
1444 void
1445 MidiTimeAxisView::extend_note_selection (uint8_t note)
1446 {
1447         if (!_editor.internal_editing()) {
1448                 return;
1449         }
1450
1451         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1452
1453         if (_view->num_selected_regionviews() == 0) {
1454                 _view->foreach_regionview (
1455                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1456                                     note, chn_mask));
1457         } else {
1458                 _view->foreach_selected_regionview (
1459                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1460                                     note, chn_mask));
1461         }
1462 }
1463
1464 void
1465 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1466 {
1467         if (!_editor.internal_editing()) {
1468                 return;
1469         }
1470
1471         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1472
1473         if (_view->num_selected_regionviews() == 0) {
1474                 _view->foreach_regionview (
1475                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1476                                     note, chn_mask));
1477         } else {
1478                 _view->foreach_selected_regionview (
1479                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1480                                     note, chn_mask));
1481         }
1482 }
1483
1484 void
1485 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1486 {
1487         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1488 }
1489
1490 void
1491 MidiTimeAxisView::add_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, true, false);
1494 }
1495
1496 void
1497 MidiTimeAxisView::extend_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, true);
1500 }
1501
1502 void
1503 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1504 {
1505         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1506 }
1507
1508 void
1509 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1510 {
1511         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1512            the right ones.
1513         */
1514
1515         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1516         bool changed = false;
1517
1518         no_redraw = true;
1519
1520         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1521
1522                 for (uint32_t chn = 0; chn < 16; ++chn) {
1523                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1524                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1525
1526                         if (!track) {
1527                                 continue;
1528                         }
1529
1530                         if ((selected_channels & (0x0001 << chn)) == 0) {
1531                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1532                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1533                                 */
1534                                 changed = track->set_marked_for_display (false) || changed;
1535                         } else {
1536                                 changed = track->set_marked_for_display (true) || changed;
1537                         }
1538                 }
1539         }
1540
1541         no_redraw = false;
1542
1543         /* TODO: Bender, Pressure */
1544
1545         /* invalidate the controller menu, so that we rebuild it next time */
1546         _controller_menu_map.clear ();
1547         delete controller_menu;
1548         controller_menu = 0;
1549
1550         if (changed) {
1551                 request_redraw ();
1552         }
1553 }
1554
1555 Gtk::CheckMenuItem*
1556 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1557 {
1558         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1559         if (m) {
1560                 return m;
1561         }
1562
1563         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1564         if (i != _controller_menu_map.end()) {
1565                 return i->second;
1566         }
1567
1568         i = _channel_command_menu_map.find (param);
1569         if (i != _channel_command_menu_map.end()) {
1570                 return i->second;
1571         }
1572
1573         return 0;
1574 }
1575
1576 boost::shared_ptr<MidiRegion>
1577 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1578 {
1579         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1580
1581         real_editor->begin_reversible_command (Operations::create_region);
1582         playlist()->clear_changes ();
1583
1584         real_editor->snap_to (pos, 0);
1585
1586         boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1587         PropertyList plist;
1588
1589         plist.add (ARDOUR::Properties::start, 0);
1590         plist.add (ARDOUR::Properties::length, length);
1591         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1592
1593         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1594
1595         playlist()->add_region (region, pos);
1596         _session->add_command (new StatefulDiffCommand (playlist()));
1597
1598         if (commit) {
1599                 real_editor->commit_reversible_command ();
1600         }
1601
1602         return boost::dynamic_pointer_cast<MidiRegion>(region);
1603 }
1604
1605 void
1606 MidiTimeAxisView::ensure_step_editor ()
1607 {
1608         if (!_step_editor) {
1609                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1610         }
1611 }
1612
1613 void
1614 MidiTimeAxisView::start_step_editing ()
1615 {
1616         ensure_step_editor ();
1617         _step_editor->start_step_editing ();
1618
1619 }
1620 void
1621 MidiTimeAxisView::stop_step_editing ()
1622 {
1623         if (_step_editor) {
1624                 _step_editor->stop_step_editing ();
1625         }
1626 }
1627
1628 /** @return channel (counted from 0) to add an event to, based on the current setting
1629  *  of the channel selector.
1630  */
1631 uint8_t
1632 MidiTimeAxisView::get_channel_for_add () const
1633 {
1634         uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1635         int chn_cnt = 0;
1636         uint8_t channel = 0;
1637
1638         /* pick the highest selected channel, unless all channels are selected,
1639            which is interpreted to mean channel 1 (zero)
1640         */
1641
1642         for (uint16_t i = 0; i < 16; ++i) {
1643                 if (chn_mask & (1<<i)) {
1644                         channel = i;
1645                         chn_cnt++;
1646                 }
1647         }
1648
1649         if (chn_cnt == 16) {
1650                 channel = 0;
1651         }
1652
1653         return channel;
1654 }
1655
1656 void
1657 MidiTimeAxisView::note_range_changed ()
1658 {
1659         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1660         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1661 }
1662
1663 void
1664 MidiTimeAxisView::contents_height_changed ()
1665 {
1666         _range_scroomer->set_size_request (-1, _view->child_height ());
1667 }
1668
1669 void
1670 MidiTimeAxisView::playback_channel_mode_changed ()
1671 {
1672         switch (midi_track()->get_playback_channel_mode()) {
1673         case AllChannels:
1674                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1675                 break;
1676         case FilterChannels:
1677                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1678                 break;
1679         case ForceChannel:
1680                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1681                 break;
1682         }
1683 }
1684
1685 void
1686 MidiTimeAxisView::capture_channel_mode_changed ()
1687 {
1688         switch (midi_track()->get_capture_channel_mode()) {
1689         case AllChannels:
1690                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1691                 break;
1692         case FilterChannels:
1693                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1694                 break;
1695         case ForceChannel:
1696                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1697                 break;
1698         }
1699 }