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