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