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