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