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