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