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