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