Remove internal edit mode and add "content" tool.
[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::check_step_edit ()
409 {
410         ensure_step_editor ();
411         _step_editor->check_step_edit ();
412 }
413
414 void
415 MidiTimeAxisView::model_changed(const std::string& model)
416 {
417         set_gui_property (X_("midnam-model-name"), model);
418
419         const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
420                 .custom_device_mode_names_by_model(model);
421
422         _midnam_model_selector.set_text(model);
423         _midnam_custom_device_mode_selector.clear_items();
424
425         for (std::list<std::string>::const_iterator i = device_modes.begin();
426              i != device_modes.end(); ++i) {
427                 _midnam_custom_device_mode_selector.AddMenuElem(
428                         Gtk::Menu_Helpers::MenuElem(
429                                 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
430                                                *i)));
431         }
432
433         if (!device_modes.empty()) {
434                 custom_device_mode_changed(device_modes.front());
435         }
436
437         if (device_modes.size() > 1) {
438                 _midnam_custom_device_mode_selector.show();
439         } else {
440                 _midnam_custom_device_mode_selector.hide();
441         }
442
443         _route->instrument_info().set_external_instrument (model, device_modes.front());
444
445         // Rebuild controller menu
446         _controller_menu_map.clear ();
447         delete controller_menu;
448         controller_menu = 0;
449         build_automation_action_menu(false);
450 }
451
452 void
453 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
454 {
455         const std::string model = gui_property (X_("midnam-model-name"));
456
457         set_gui_property (X_("midnam-custom-device-mode"), mode);
458         _midnam_custom_device_mode_selector.set_text(mode);
459         _route->instrument_info().set_external_instrument (model, mode);
460 }
461
462 MidiStreamView*
463 MidiTimeAxisView::midi_view()
464 {
465         return dynamic_cast<MidiStreamView*>(_view);
466 }
467
468 void
469 MidiTimeAxisView::set_height (uint32_t h)
470 {
471         if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
472                 _midi_controls_box.show ();
473         } else {
474                 _midi_controls_box.hide();
475         }
476         
477         if (h >= KEYBOARD_MIN_HEIGHT) {
478                 if (is_track() && _range_scroomer) {
479                         _range_scroomer->show();
480                 }
481                 if (is_track() && _piano_roll_header) {
482                         _piano_roll_header->show();
483                 }
484         } else {
485                 if (is_track() && _range_scroomer) {
486                         _range_scroomer->hide();
487                 }
488                 if (is_track() && _piano_roll_header) {
489                         _piano_roll_header->hide();
490                 }
491         }
492
493         /* We need to do this after changing visibility of our stuff, as it will
494            eventually trigger a call to Editor::reset_controls_layout_width(),
495            which needs to know if we have just shown or hidden a scroomer /
496            piano roll.
497         */
498         RouteTimeAxisView::set_height (h);
499 }
500
501 void
502 MidiTimeAxisView::append_extra_display_menu_items ()
503 {
504         using namespace Menu_Helpers;
505
506         MenuList& items = display_menu->items();
507
508         // Note range
509         Menu *range_menu = manage(new Menu);
510         MenuList& range_items = range_menu->items();
511         range_menu->set_name ("ArdourContextMenu");
512
513         range_items.push_back (
514                 MenuElem (_("Show Full Range"),
515                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range), 
516                                       MidiStreamView::FullRange, true)));
517
518         range_items.push_back (
519                 MenuElem (_("Fit Contents"),
520                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
521                                       MidiStreamView::ContentsRange, true)));
522
523         items.push_back (MenuElem (_("Note Range"), *range_menu));
524         items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
525         items.push_back (MenuElem (_("Channel Selector"),
526                                    sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
527
528         color_mode_menu = build_color_mode_menu();
529         if (color_mode_menu) {
530                 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
531         }
532         
533         items.push_back (SeparatorElem ());
534 }
535
536 void
537 MidiTimeAxisView::toggle_channel_selector ()
538 {
539         if (!_channel_selector) {
540                 _channel_selector = new MidiChannelSelectorWindow (midi_track());
541
542                 if (_color_mode == ChannelColors) {
543                         _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
544                 } else {
545                         _channel_selector->set_default_channel_color ();
546                 }
547
548                 _channel_selector->show_all ();
549         } else {
550                 _channel_selector->cycle_visibility ();
551         }
552 }
553
554 void
555 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
556 {
557         using namespace Menu_Helpers;
558
559         /* If we have a controller menu, we need to detach it before
560            RouteTimeAxis::build_automation_action_menu destroys the
561            menu it is attached to.  Otherwise GTK destroys
562            controller_menu's gobj, meaning that it can't be reattached
563            below.  See bug #3134.
564         */
565
566         if (controller_menu) {
567                 detach_menu (*controller_menu);
568         }
569
570         _channel_command_menu_map.clear ();
571         RouteTimeAxisView::build_automation_action_menu (for_selection);
572
573         MenuList& automation_items = automation_action_menu->items();
574
575         uint16_t selected_channels = midi_track()->get_playback_channel_mask();
576
577         if (selected_channels !=  0) {
578
579                 automation_items.push_back (SeparatorElem());
580
581                 /* these 2 MIDI "command" types are semantically more like automation
582                    than note data, but they are not MIDI controllers. We give them
583                    special status in this menu, since they will not show up in the
584                    controller list and anyone who actually knows something about MIDI
585                    (!) would not expect to find them there.
586                 */
587
588                 add_channel_command_menu_item (
589                         automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
590                 automation_items.back().set_sensitive (
591                         !for_selection || _editor.get_selection().tracks.size() == 1);
592                 add_channel_command_menu_item (
593                         automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
594                 automation_items.back().set_sensitive (
595                         !for_selection || _editor.get_selection().tracks.size() == 1);
596
597                 /* now all MIDI controllers. Always offer the possibility that we will
598                    rebuild the controllers menu since it might need to be updated after
599                    a channel mode change or other change. Also detach it first in case
600                    it has been used anywhere else.
601                 */
602
603                 build_controller_menu ();
604
605                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
606                 automation_items.back().set_sensitive (
607                         !for_selection || _editor.get_selection().tracks.size() == 1);
608         } else {
609                 automation_items.push_back (
610                         MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
611                 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
612         }
613 }
614
615 void
616 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
617 {
618         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
619
620         for (uint8_t chn = 0; chn < 16; chn++) {
621                 if (selected_channels & (0x0001 << chn)) {
622
623                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
624                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
625
626                         if (menu) {
627                                 menu->set_active (yn);
628                         }
629                 }
630         }
631 }
632
633 void
634 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
635                                                  const string&           label,
636                                                  AutomationType          auto_type,
637                                                  uint8_t                 cmd)
638 {
639         using namespace Menu_Helpers;
640
641         /* count the number of selected channels because we will build a different menu
642            structure if there is more than 1 selected.
643          */
644
645         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
646         int chn_cnt = 0;
647
648         for (uint8_t chn = 0; chn < 16; chn++) {
649                 if (selected_channels & (0x0001 << chn)) {
650                         if (++chn_cnt > 1) {
651                                 break;
652                         }
653                 }
654         }
655
656         if (chn_cnt > 1) {
657
658                 /* multiple channels - create a submenu, with 1 item per channel */
659
660                 Menu* chn_menu = manage (new Menu);
661                 MenuList& chn_items (chn_menu->items());
662                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
663
664                 /* add a couple of items to hide/show all of them */
665
666                 chn_items.push_back (
667                         MenuElem (_("Hide all channels"),
668                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
669                                               false, param_without_channel)));
670                 chn_items.push_back (
671                         MenuElem (_("Show all channels"),
672                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
673                                               true, param_without_channel)));
674
675                 for (uint8_t chn = 0; chn < 16; chn++) {
676                         if (selected_channels & (0x0001 << chn)) {
677
678                                 /* for each selected channel, add a menu item for this controller */
679
680                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
681                                 chn_items.push_back (
682                                         CheckMenuElem (string_compose (_("Channel %1"), chn+1),
683                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
684                                                                    fully_qualified_param)));
685
686                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
687                                 bool visible = false;
688
689                                 if (track) {
690                                         if (track->marked_for_display()) {
691                                                 visible = true;
692                                         }
693                                 }
694
695                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
696                                 _channel_command_menu_map[fully_qualified_param] = cmi;
697                                 cmi->set_active (visible);
698                         }
699                 }
700
701                 /* now create an item in the parent menu that has the per-channel list as a submenu */
702
703                 items.push_back (MenuElem (label, *chn_menu));
704
705         } else {
706
707                 /* just one channel - create a single menu item for this command+channel combination*/
708
709                 for (uint8_t chn = 0; chn < 16; chn++) {
710                         if (selected_channels & (0x0001 << chn)) {
711
712                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
713                                 items.push_back (
714                                         CheckMenuElem (label,
715                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
716                                                                    fully_qualified_param)));
717
718                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
719                                 bool visible = false;
720
721                                 if (track) {
722                                         if (track->marked_for_display()) {
723                                                 visible = true;
724                                         }
725                                 }
726
727                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
728                                 _channel_command_menu_map[fully_qualified_param] = cmi;
729                                 cmi->set_active (visible);
730
731                                 /* one channel only */
732                                 break;
733                         }
734                 }
735         }
736 }
737
738 /** Add a single menu item for a controller on one channel. */
739 void
740 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
741                                                      int                     ctl,
742                                                      const std::string&      name)
743 {
744         using namespace Menu_Helpers;
745
746         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
747         for (uint8_t chn = 0; chn < 16; chn++) {
748                 if (selected_channels & (0x0001 << chn)) {
749
750                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
751                         ctl_items.push_back (
752                                 CheckMenuElem (
753                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
754                                         sigc::bind (
755                                                 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
756                                                 fully_qualified_param)));
757                         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
758
759                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
760                                 fully_qualified_param);
761
762                         bool visible = false;
763                         if (track) {
764                                 if (track->marked_for_display()) {
765                                         visible = true;
766                                 }
767                         }
768
769                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
770                         _controller_menu_map[fully_qualified_param] = cmi;
771                         cmi->set_active (visible);
772
773                         /* one channel only */
774                         break;
775                 }
776         }
777 }
778
779 /** Add a submenu with 1 item per channel for a controller on many channels. */
780 void
781 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
782                                                     int                     ctl,
783                                                     const std::string&      name)
784 {
785         using namespace Menu_Helpers;
786
787         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
788
789         Menu* chn_menu = manage (new Menu);
790         MenuList& chn_items (chn_menu->items());
791
792         /* add a couple of items to hide/show this controller on all channels */
793
794         Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
795         chn_items.push_back (
796                 MenuElem (_("Hide all channels"),
797                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
798                                       false, param_without_channel)));
799         chn_items.push_back (
800                 MenuElem (_("Show all channels"),
801                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
802                                       true, param_without_channel)));
803
804         for (uint8_t chn = 0; chn < 16; chn++) {
805                 if (selected_channels & (0x0001 << chn)) {
806
807                         /* for each selected channel, add a menu item for this controller */
808
809                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
810                         chn_items.push_back (
811                                 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
812                                                sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
813                                                            fully_qualified_param)));
814
815                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
816                                 fully_qualified_param);
817                         bool visible = false;
818
819                         if (track) {
820                                 if (track->marked_for_display()) {
821                                         visible = true;
822                                 }
823                         }
824
825                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
826                         _controller_menu_map[fully_qualified_param] = cmi;
827                         cmi->set_active (visible);
828                 }
829         }
830
831         /* add the per-channel menu to the list of controllers, with the name of the controller */
832         ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
833                                        *chn_menu));
834         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
835 }
836
837 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
838 MidiTimeAxisView::get_device_mode()
839 {
840         using namespace MIDI::Name;
841
842         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
843         if (!device_names) {
844                 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
845         }
846
847         return device_names->custom_device_mode_by_name(
848                 gui_property (X_("midnam-custom-device-mode")));
849 }
850
851 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
852 MidiTimeAxisView::get_device_names()
853 {
854         using namespace MIDI::Name;
855
856         const std::string model = gui_property (X_("midnam-model-name"));
857
858         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
859                 .document_by_model(model);
860         if (midnam) {
861                 return midnam->master_device_names(model);
862         } else {
863                 return boost::shared_ptr<MasterDeviceNames>();
864         }
865 }
866
867 void
868 MidiTimeAxisView::build_controller_menu ()
869 {
870         using namespace Menu_Helpers;
871
872         if (controller_menu) {
873                 /* it exists and has not been invalidated by a channel mode change */
874                 return;
875         }
876
877         controller_menu = new Menu; // explicitly managed by us
878         MenuList& items (controller_menu->items());
879
880         /* create several "top level" menu items for sets of controllers (16 at a
881            time), and populate each one with a submenu for each controller+channel
882            combination covering the currently selected channels for this track
883         */
884
885         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
886
887         /* count the number of selected channels because we will build a different menu
888            structure if there is more than 1 selected.
889         */
890
891         int chn_cnt = 0;
892         for (uint8_t chn = 0; chn < 16; chn++) {
893                 if (selected_channels & (0x0001 << chn)) {
894                         if (++chn_cnt > 1) {
895                                 break;
896                         }
897                 }
898         }
899
900         using namespace MIDI::Name;
901         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
902
903         if (device_names && !device_names->controls().empty()) {
904                 /* Controllers names available in midnam file, generate fancy menu */
905                 unsigned n_items  = 0;
906                 unsigned n_groups = 0;
907
908                 /* TODO: This is not correct, should look up the currently applicable ControlNameList
909                    and only build a menu for that one. */
910                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
911                      l != device_names->controls().end(); ++l) {
912                         boost::shared_ptr<ControlNameList> name_list = l->second;
913                         Menu*                              ctl_menu  = NULL;
914                         
915                         for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
916                              c != name_list->controls().end();) {
917                                 const uint16_t ctl = c->second->number();
918                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
919                                         /* Skip bank select controllers since they're handled specially */
920                                         if (n_items == 0) {
921                                                 /* Create a new submenu */
922                                                 ctl_menu = manage (new Menu);
923                                         }
924                                 
925                                         MenuList& ctl_items (ctl_menu->items());
926                                         if (chn_cnt > 1) {
927                                                 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
928                                         } else {
929                                                 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
930                                         }
931                                 }
932
933                                 ++c;
934                                 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
935                                         /* Submenu has 16 items or we're done, add it to controller menu and reset */
936                                         items.push_back(
937                                                 MenuElem(string_compose(_("Controllers %1-%2"),
938                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
939                                                          *ctl_menu));
940                                         ctl_menu = NULL;
941                                         n_items  = 0;
942                                         ++n_groups;
943                                 }
944                         }
945                 }
946         } else {
947                 /* No controllers names, generate generic numeric menu */
948                 for (int i = 0; i < 127; i += 16) {
949                         Menu*     ctl_menu = manage (new Menu);
950                         MenuList& ctl_items (ctl_menu->items());
951
952                         for (int ctl = i; ctl < i+16; ++ctl) {
953                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
954                                         /* Skip bank select controllers since they're handled specially */
955                                         continue;
956                                 }
957
958                                 if (chn_cnt > 1) {
959                                         add_multi_channel_controller_item(
960                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
961                                 } else {
962                                         add_single_channel_controller_item(
963                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
964                                 }
965                         }
966
967                         /* Add submenu for this block of controllers to controller menu */
968                         items.push_back (
969                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
970                                           *ctl_menu));
971                 }
972         }
973 }
974
975 Gtk::Menu*
976 MidiTimeAxisView::build_note_mode_menu()
977 {
978         using namespace Menu_Helpers;
979
980         Menu* mode_menu = manage (new Menu);
981         MenuList& items = mode_menu->items();
982         mode_menu->set_name ("ArdourContextMenu");
983
984         RadioMenuItem::Group mode_group;
985         items.push_back (
986                 RadioMenuElem (mode_group,_("Sustained"),
987                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
988                                            Sustained, true)));
989         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
990         _note_mode_item->set_active(_note_mode == Sustained);
991
992         items.push_back (
993                 RadioMenuElem (mode_group, _("Percussive"),
994                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
995                                            Percussive, true)));
996         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
997         _percussion_mode_item->set_active(_note_mode == Percussive);
998
999         return mode_menu;
1000 }
1001
1002 Gtk::Menu*
1003 MidiTimeAxisView::build_color_mode_menu()
1004 {
1005         using namespace Menu_Helpers;
1006
1007         Menu* mode_menu = manage (new Menu);
1008         MenuList& items = mode_menu->items();
1009         mode_menu->set_name ("ArdourContextMenu");
1010
1011         RadioMenuItem::Group mode_group;
1012         items.push_back (
1013                 RadioMenuElem (mode_group, _("Meter Colors"),
1014                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1015                                            MeterColors, false, true, true)));
1016         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1017         _meter_color_mode_item->set_active(_color_mode == MeterColors);
1018
1019         items.push_back (
1020                 RadioMenuElem (mode_group, _("Channel Colors"),
1021                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1022                                            ChannelColors, false, true, true)));
1023         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1024         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1025
1026         items.push_back (
1027                 RadioMenuElem (mode_group, _("Track Color"),
1028                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1029                                            TrackColor, false, true, true)));
1030         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1031         _channel_color_mode_item->set_active(_color_mode == TrackColor);
1032
1033         return mode_menu;
1034 }
1035
1036 void
1037 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1038 {
1039         if (apply_to_selection) {
1040                 _editor.get_selection().tracks.foreach_midi_time_axis (
1041                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1042         } else {
1043                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1044                         _note_mode = mode;
1045                         midi_track()->set_note_mode(mode);
1046                         set_gui_property ("note-mode", enum_2_string(_note_mode));
1047                         _view->redisplay_track();
1048                 }
1049         }
1050 }
1051
1052 void
1053 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1054 {
1055         if (apply_to_selection) {
1056                 _editor.get_selection().tracks.foreach_midi_time_axis (
1057                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1058         } else {
1059                 if (_color_mode == mode && !force) {
1060                         return;
1061                 }
1062                 
1063                 if (_channel_selector) {
1064                         if (mode == ChannelColors) {
1065                                 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1066                         } else {
1067                                 _channel_selector->set_default_channel_color();
1068                         }
1069                 }
1070                 
1071                 _color_mode = mode;
1072                 set_gui_property ("color-mode", enum_2_string(_color_mode));
1073                 if (redisplay) {
1074                         _view->redisplay_track();
1075                 }
1076         }
1077 }
1078
1079 void
1080 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1081 {
1082         if (apply_to_selection) {
1083                 _editor.get_selection().tracks.foreach_midi_time_axis (
1084                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1085         } else {
1086                 if (!_ignore_signals) {
1087                         midi_view()->set_note_range(range);
1088                 }
1089         }
1090 }
1091
1092 void
1093 MidiTimeAxisView::update_range()
1094 {
1095         MidiGhostRegion* mgr;
1096
1097         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1098                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1099                         mgr->update_range();
1100                 }
1101         }
1102 }
1103
1104 void
1105 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1106 {
1107         using namespace MIDI::Name;
1108
1109         if (apply_to_selection) {
1110                 _editor.get_selection().tracks.foreach_midi_time_axis (
1111                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1112         } else {
1113                 if (midi_track()) {
1114                         // Show existing automation
1115                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1116
1117                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1118                                 create_automation_child(*i, true);
1119                         }
1120
1121                         // Show automation for all controllers named in midnam file
1122                         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1123                         if (gui_property (X_("midnam-model-name")) != "Generic" &&
1124                              device_names && !device_names->controls().empty()) {
1125                                 const std::string device_mode       = gui_property (X_("midnam-custom-device-mode"));
1126                                 const uint16_t    selected_channels = midi_track()->get_playback_channel_mask();
1127                                 for (uint32_t chn = 0; chn < 16; ++chn) {
1128                                         if ((selected_channels & (0x0001 << chn)) == 0) {
1129                                                 // Channel not in use
1130                                                 continue;
1131                                         }
1132
1133                                         boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1134                                                 device_mode, chn);
1135                                         if (!chan_names) {
1136                                                 continue;
1137                                         }
1138
1139                                         boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1140                                                 chan_names->control_list_name());
1141                                         if (!control_names) {
1142                                                 continue;
1143                                         }
1144
1145                                         for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1146                                              c != control_names->controls().end();
1147                                              ++c) {
1148                                                 const uint16_t ctl = c->second->number();
1149                                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1150                                                         /* Skip bank select controllers since they're handled specially */
1151                                                         const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1152                                                         create_automation_child(param, true);
1153                                                 }
1154                                         }
1155                                 }
1156                         }
1157                 }
1158
1159                 RouteTimeAxisView::show_all_automation ();
1160         }
1161 }
1162
1163 void
1164 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1165 {
1166         if (apply_to_selection) {
1167                 _editor.get_selection().tracks.foreach_midi_time_axis (
1168                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1169         } else {
1170                 if (midi_track()) {
1171                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1172
1173                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1174                                 create_automation_child (*i, true);
1175                         }
1176                 }
1177
1178                 RouteTimeAxisView::show_existing_automation ();
1179         }
1180 }
1181
1182 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1183  */
1184 void
1185 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1186 {
1187         if (param.type() == NullAutomation) {
1188                 return;
1189         }
1190
1191         AutomationTracks::iterator existing = _automation_tracks.find (param);
1192
1193         if (existing != _automation_tracks.end()) {
1194
1195                 /* automation track created because we had existing data for
1196                  * the processor, but visibility may need to be controlled
1197                  * since it will have been set visible by default.
1198                  */
1199
1200                 existing->second->set_marked_for_display (show);
1201
1202                 if (!no_redraw) {
1203                         request_redraw ();
1204                 }
1205
1206                 return;
1207         }
1208
1209         boost::shared_ptr<AutomationTimeAxisView> track;
1210         boost::shared_ptr<AutomationControl> control;
1211
1212
1213         switch (param.type()) {
1214
1215         case GainAutomation:
1216                 create_gain_automation_child (param, show);
1217                 break;
1218
1219         case MuteAutomation:
1220                 create_mute_automation_child (param, show);
1221                 break;
1222
1223         case PluginAutomation:
1224                 /* handled elsewhere */
1225                 break;
1226
1227         case MidiCCAutomation:
1228         case MidiPgmChangeAutomation:
1229         case MidiPitchBenderAutomation:
1230         case MidiChannelPressureAutomation:
1231         case MidiSystemExclusiveAutomation:
1232                 /* These controllers are region "automation" - they are owned
1233                  * by regions (and their MidiModels), not by the track. As a
1234                  * result there is no AutomationList/Line for the track, but we create
1235                  * a controller for the user to write immediate events, so the editor
1236                  * can act as a control surface for the present MIDI controllers.
1237                  *
1238                  * TODO: Record manipulation of the controller to regions?
1239                  */
1240
1241                 control = _route->automation_control(param, true);
1242                 track.reset (new AutomationTimeAxisView (
1243                                      _session,
1244                                      _route,
1245                                      control ? _route : boost::shared_ptr<Automatable> (),
1246                                      control,
1247                                      param,
1248                                      _editor,
1249                                      *this,
1250                                      true,
1251                                      parent_canvas,
1252                                      _route->describe_parameter(param)));
1253
1254                 if (_view) {
1255                         _view->foreach_regionview (
1256                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1257                 }
1258
1259                 add_automation_child (param, track, show);
1260                 break;
1261
1262         case PanWidthAutomation:
1263         case PanElevationAutomation:
1264         case PanAzimuthAutomation:
1265                 ensure_pan_views (show);
1266                 break;
1267
1268         default:
1269                 error << "MidiTimeAxisView: unknown automation child "
1270                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1271         }
1272 }
1273
1274 void
1275 MidiTimeAxisView::route_active_changed ()
1276 {
1277         RouteUI::route_active_changed ();
1278
1279         if (is_track()) {
1280                 if (_route->active()) {
1281                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1282                         time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1283                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1284                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1285                 } else {
1286                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1287                         time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1288                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1289                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1290                 }
1291         } else {
1292                 if (_route->active()) {
1293                         controls_ebox.set_name ("BusControlsBaseUnselected");
1294                         time_axis_frame.set_name ("BusControlsBaseUnselected");
1295                         controls_base_selected_name = "BusControlsBaseSelected";
1296                         controls_base_unselected_name = "BusControlsBaseUnselected";
1297                 } else {
1298                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1299                         time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1300                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1301                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1302                 }
1303         }
1304 }
1305
1306 void
1307 MidiTimeAxisView::set_note_selection (uint8_t note)
1308 {
1309         uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1310
1311         if (_view->num_selected_regionviews() == 0) {
1312                 _view->foreach_regionview (
1313                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1314                                     note, chn_mask));
1315         } else {
1316                 _view->foreach_selected_regionview (
1317                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1318                                     note, chn_mask));
1319         }
1320 }
1321
1322 void
1323 MidiTimeAxisView::add_note_selection (uint8_t note)
1324 {
1325         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1326
1327         if (_view->num_selected_regionviews() == 0) {
1328                 _view->foreach_regionview (
1329                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1330                                     note, chn_mask));
1331         } else {
1332                 _view->foreach_selected_regionview (
1333                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1334                                     note, chn_mask));
1335         }
1336 }
1337
1338 void
1339 MidiTimeAxisView::extend_note_selection (uint8_t note)
1340 {
1341         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1342
1343         if (_view->num_selected_regionviews() == 0) {
1344                 _view->foreach_regionview (
1345                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1346                                     note, chn_mask));
1347         } else {
1348                 _view->foreach_selected_regionview (
1349                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1350                                     note, chn_mask));
1351         }
1352 }
1353
1354 void
1355 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1356 {
1357         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1358
1359         if (_view->num_selected_regionviews() == 0) {
1360                 _view->foreach_regionview (
1361                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1362                                     note, chn_mask));
1363         } else {
1364                 _view->foreach_selected_regionview (
1365                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1366                                     note, chn_mask));
1367         }
1368 }
1369
1370 void
1371 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1372 {
1373         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1374 }
1375
1376 void
1377 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1378 {
1379         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1380 }
1381
1382 void
1383 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1384 {
1385         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1386 }
1387
1388 void
1389 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1390 {
1391         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1392 }
1393
1394 void
1395 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1396 {
1397         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1398            the right ones.
1399         */
1400
1401         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1402         bool changed = false;
1403
1404         no_redraw = true;
1405
1406         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1407
1408                 for (uint32_t chn = 0; chn < 16; ++chn) {
1409                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1410                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1411
1412                         if (!track) {
1413                                 continue;
1414                         }
1415
1416                         if ((selected_channels & (0x0001 << chn)) == 0) {
1417                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1418                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1419                                 */
1420                                 changed = track->set_marked_for_display (false) || changed;
1421                         } else {
1422                                 changed = track->set_marked_for_display (true) || changed;
1423                         }
1424                 }
1425         }
1426
1427         no_redraw = false;
1428
1429         /* TODO: Bender, Pressure */
1430
1431         /* invalidate the controller menu, so that we rebuild it next time */
1432         _controller_menu_map.clear ();
1433         delete controller_menu;
1434         controller_menu = 0;
1435
1436         if (changed) {
1437                 request_redraw ();
1438         }
1439 }
1440
1441 Gtk::CheckMenuItem*
1442 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1443 {
1444         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1445         if (m) {
1446                 return m;
1447         }
1448
1449         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1450         if (i != _controller_menu_map.end()) {
1451                 return i->second;
1452         }
1453
1454         i = _channel_command_menu_map.find (param);
1455         if (i != _channel_command_menu_map.end()) {
1456                 return i->second;
1457         }
1458
1459         return 0;
1460 }
1461
1462 boost::shared_ptr<MidiRegion>
1463 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1464 {
1465         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1466
1467         real_editor->begin_reversible_command (Operations::create_region);
1468         playlist()->clear_changes ();
1469
1470         real_editor->snap_to (pos, RoundNearest);
1471
1472         boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1473         PropertyList plist;
1474
1475         plist.add (ARDOUR::Properties::start, 0);
1476         plist.add (ARDOUR::Properties::length, length);
1477         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1478
1479         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1480
1481         playlist()->add_region (region, pos);
1482         _session->add_command (new StatefulDiffCommand (playlist()));
1483
1484         if (commit) {
1485                 real_editor->commit_reversible_command ();
1486         }
1487
1488         return boost::dynamic_pointer_cast<MidiRegion>(region);
1489 }
1490
1491 void
1492 MidiTimeAxisView::ensure_step_editor ()
1493 {
1494         if (!_step_editor) {
1495                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1496         }
1497 }
1498
1499 void
1500 MidiTimeAxisView::start_step_editing ()
1501 {
1502         ensure_step_editor ();
1503         _step_editor->start_step_editing ();
1504
1505 }
1506 void
1507 MidiTimeAxisView::stop_step_editing ()
1508 {
1509         if (_step_editor) {
1510                 _step_editor->stop_step_editing ();
1511         }
1512 }
1513
1514 /** @return channel (counted from 0) to add an event to, based on the current setting
1515  *  of the channel selector.
1516  */
1517 uint8_t
1518 MidiTimeAxisView::get_channel_for_add () const
1519 {
1520         uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1521         int chn_cnt = 0;
1522         uint8_t channel = 0;
1523
1524         /* pick the highest selected channel, unless all channels are selected,
1525            which is interpreted to mean channel 1 (zero)
1526         */
1527
1528         for (uint16_t i = 0; i < 16; ++i) {
1529                 if (chn_mask & (1<<i)) {
1530                         channel = i;
1531                         chn_cnt++;
1532                 }
1533         }
1534
1535         if (chn_cnt == 16) {
1536                 channel = 0;
1537         }
1538
1539         return channel;
1540 }
1541
1542 void
1543 MidiTimeAxisView::note_range_changed ()
1544 {
1545         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1546         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1547 }
1548
1549 void
1550 MidiTimeAxisView::contents_height_changed ()
1551 {
1552         _range_scroomer->queue_resize ();
1553 }
1554
1555 void
1556 MidiTimeAxisView::playback_channel_mode_changed ()
1557 {
1558         switch (midi_track()->get_playback_channel_mode()) {
1559         case AllChannels:
1560                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1561                 break;
1562         case FilterChannels:
1563                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1564                 break;
1565         case ForceChannel:
1566                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1567                 break;
1568         }
1569 }
1570
1571 void
1572 MidiTimeAxisView::capture_channel_mode_changed ()
1573 {
1574         switch (midi_track()->get_capture_channel_mode()) {
1575         case AllChannels:
1576                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1577                 break;
1578         case FilterChannels:
1579                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1580                 break;
1581         case ForceChannel:
1582                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1583                 break;
1584         }
1585 }