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