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