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