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