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