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