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