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