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