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