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