Merge branch 'patches' of https://github.com/jdekozak/ardour
[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 "canvas-note-event.h"
65 #include "canvas_impl.h"
66 #include "editor.h"
67 #include "enums.h"
68 #include "ghostregion.h"
69 #include "gui_thread.h"
70 #include "keyboard.h"
71 #include "midi_channel_selector.h"
72 #include "midi_scroomer.h"
73 #include "midi_streamview.h"
74 #include "midi_region_view.h"
75 #include "midi_time_axis.h"
76 #include "piano_roll_header.h"
77 #include "playlist_selector.h"
78 #include "plugin_selector.h"
79 #include "plugin_ui.h"
80 #include "point_selection.h"
81 #include "prompter.h"
82 #include "region_view.h"
83 #include "rgb_macros.h"
84 #include "selection.h"
85 #include "step_editor.h"
86 #include "simplerect.h"
87 #include "utils.h"
88
89 #include "ardour/midi_track.h"
90
91 #include "i18n.h"
92
93 using namespace ARDOUR;
94 using namespace PBD;
95 using namespace Gtk;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
98
99 // Minimum height at which a control is displayed
100 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 140;
101 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
102
103 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
104         : AxisView(sess) // virtually inherited
105         , RouteTimeAxisView(ed, sess, canvas)
106         , _ignore_signals(false)
107         , _range_scroomer(0)
108         , _piano_roll_header(0)
109         , _note_mode(Sustained)
110         , _note_mode_item(0)
111         , _percussion_mode_item(0)
112         , _color_mode(MeterColors)
113         , _meter_color_mode_item(0)
114         , _channel_color_mode_item(0)
115         , _track_color_mode_item(0)
116         , _channel_selector (0)
117         , _step_edit_item (0)
118         , controller_menu (0)
119         , _step_editor (0)
120 {
121 }
122
123 void
124 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
125 {
126         _route = rt;
127         
128         _view = new MidiStreamView (*this);
129
130         if (is_track ()) {
131                 _piano_roll_header = new PianoRollHeader(*midi_view());
132                 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
133                 _range_scroomer->DoubleClicked.connect (
134                         sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
135                                     MidiStreamView::ContentsRange, false));
136         }
137
138         /* This next call will result in our height being set up, so it must come after
139            the creation of the piano roll / range scroomer as their visibility is set up
140            when our height is.
141         */
142         RouteTimeAxisView::set_route (rt);
143
144         _view->apply_color (_color, StreamView::RegionColor);
145
146         subplugin_menu.set_name ("ArdourContextMenu");
147
148         if (!gui_property ("note-range-min").empty ()) {
149                 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
150                                                atoi (gui_property ("note-range-max").c_str()),
151                                                true);
152         }
153
154         midi_view()->NoteRangeChanged.connect (
155                 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
156         _view->ContentsHeightChanged.connect (
157                 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
158
159         ignore_toggle = false;
160
161         if (is_midi_track()) {
162                 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
163                 _note_mode = midi_track()->note_mode();
164         } else { // MIDI bus (which doesn't exist yet..)
165                 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
166         }
167
168         /* map current state of the route */
169
170         processors_changed (RouteProcessorChange ());
171
172         _route->processors_changed.connect (*this, invalidator (*this),
173                                             boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
174                                             gui_context());
175
176         if (is_track()) {
177                 _piano_roll_header->SetNoteSelection.connect (
178                         sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
179                 _piano_roll_header->AddNoteSelection.connect (
180                         sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
181                 _piano_roll_header->ExtendNoteSelection.connect (
182                         sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
183                 _piano_roll_header->ToggleNoteSelection.connect (
184                         sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
185
186                 /* Suspend updates of the StreamView during scroomer drags to speed things up */
187                 _range_scroomer->DragStarting.connect (
188                         sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
189                 _range_scroomer->DragFinishing.connect (
190                         sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
191
192                 /* Put the scroomer and the keyboard in a VBox with a padding
193                    label so that they can be reduced in height for stacked-view
194                    tracks.
195                 */
196                 VBox* v = manage (new VBox);
197                 HBox* h = manage (new HBox);
198                 h->pack_start (*_range_scroomer);
199                 h->pack_start (*_piano_roll_header);
200                 v->pack_start (*h, false, false);
201                 v->pack_start (*manage (new Label ("")), true, true);
202                 v->show ();
203                 h->show ();
204                 controls_hbox.pack_start(*v);
205
206                 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
207                 controls_base_selected_name = "MidiTrackControlsBaseSelected";
208                 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
209
210                 midi_view()->NoteRangeChanged.connect (
211                         sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
212
213                 /* ask for notifications of any new RegionViews */
214                 _view->RegionViewAdded.connect (
215                         sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
216
217                 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
218                                                                   boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
219                                                                   gui_context());
220                 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
221                                                                   boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
222                                                                   gui_context());
223                 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
224                                                                   boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
225                                                                   gui_context());
226                 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
227                                                                   boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
228                                                                   gui_context());
229
230                 playback_channel_mode_changed ();
231                 capture_channel_mode_changed ();
232
233                 if (!_editor.have_idled()) {
234                         /* first idle will do what we need */
235                 } else {
236                         first_idle ();
237                 }
238         }
239
240         MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
241
242         MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
243         for (; m != patch_manager.all_models().end(); ++m) {
244                 _midnam_model_selector.append_text(m->c_str());
245         }
246
247         if (gui_property (X_("midnam-model-name")).empty()) {
248                 set_gui_property (X_("midnam-model-name"), "Generic");
249         }
250
251         if (gui_property (X_("midnam-custom-device-mode")).empty()) {
252                 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
253                 if (device_names) {
254                         set_gui_property (X_("midnam-custom-device-mode"),
255                                           *device_names->custom_device_mode_names().begin());
256                 }
257         }
258
259         _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
260         _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
261
262         ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
263         ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
264
265         _midi_controls_box.set_homogeneous(false);
266         _midi_controls_box.set_border_width (10);
267
268         _channel_status_box.set_homogeneous (false);
269         _channel_status_box.set_spacing (6);
270         
271         _channel_selector_button.set_label (_("Chns"));
272
273         /* fixed sized labels to prevent silly nonsense */
274
275         _playback_channel_status.set_size_request (65, -1);
276         _capture_channel_status.set_size_request (60, -1);
277
278         _channel_status_box.pack_start (_playback_channel_status, false, false);
279         _channel_status_box.pack_start (_capture_channel_status, false, false);
280         _channel_status_box.pack_start (_channel_selector_button, false, false);
281         _channel_status_box.show_all ();
282
283         _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
284         
285         _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
286
287         if (!patch_manager.all_models().empty()) {
288
289                 _midnam_model_selector.set_size_request(22, 30);
290                 _midnam_model_selector.set_border_width(2);
291                 _midnam_model_selector.show ();
292                 _midi_controls_box.pack_start (_midnam_model_selector);
293
294                 _midnam_custom_device_mode_selector.set_size_request(10, 30);
295                 _midnam_custom_device_mode_selector.set_border_width(2);
296                 _midnam_custom_device_mode_selector.show ();
297
298                 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
299         } 
300
301         model_changed();
302         custom_device_mode_changed();
303
304         _midnam_model_selector.signal_changed().connect(
305                 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
306         _midnam_custom_device_mode_selector.signal_changed().connect(
307                 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
308
309         controls_vbox.pack_start(_midi_controls_box, false, false);
310
311         const string color_mode = gui_property ("color-mode");
312         if (!color_mode.empty()) {
313                 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
314                 if (_channel_selector && _color_mode == ChannelColors) {
315                         _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
316                 }
317         }
318
319         set_color_mode (_color_mode, true, false);
320
321         const string note_mode = gui_property ("note-mode");
322         if (!note_mode.empty()) {
323                 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
324                 if (_percussion_mode_item) {
325                         _percussion_mode_item->set_active (_note_mode == Percussive);
326                 }
327         }
328
329         /* Look for any GUI object state nodes that represent automation children
330          * that should exist, and create the children.
331          */
332
333         const list<string> gui_ids = gui_object_state().all_ids ();
334         for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
335                 PBD::ID route_id;
336                 bool has_parameter;
337                 Evoral::Parameter parameter (0, 0, 0);
338
339                 bool const p = AutomationTimeAxisView::parse_state_id (
340                         *i, route_id, has_parameter, parameter);
341                 if (p && route_id == _route->id () && has_parameter) {
342                         const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
343                         create_automation_child (parameter, string_is_affirmative (visible));
344                 }
345         }
346 }
347
348 void
349 MidiTimeAxisView::first_idle ()
350 {
351         if (is_track ()) {
352                 _view->attach ();
353         }
354 }
355
356 MidiTimeAxisView::~MidiTimeAxisView ()
357 {
358         delete _channel_selector;
359
360         delete _piano_roll_header;
361         _piano_roll_header = 0;
362
363         delete _range_scroomer;
364         _range_scroomer = 0;
365
366         delete controller_menu;
367         delete _step_editor;
368 }
369
370 void
371 MidiTimeAxisView::enter_internal_edit_mode ()
372 {
373         if (midi_view()) {
374                 midi_view()->enter_internal_edit_mode ();
375         }
376 }
377
378 void
379 MidiTimeAxisView::leave_internal_edit_mode ()
380 {
381         if (midi_view()) {
382                 midi_view()->leave_internal_edit_mode ();
383         }
384 }
385
386 void
387 MidiTimeAxisView::check_step_edit ()
388 {
389         ensure_step_editor ();
390         _step_editor->check_step_edit ();
391 }
392
393 void
394 MidiTimeAxisView::model_changed()
395 {
396         const Glib::ustring model = _midnam_model_selector.get_active_text();
397         set_gui_property (X_("midnam-model-name"), model);
398
399         const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
400                 .custom_device_mode_names_by_model(model);
401
402         _midnam_custom_device_mode_selector.clear_items();
403
404         for (std::list<std::string>::const_iterator i = device_modes.begin();
405              i != device_modes.end(); ++i) {
406                 _midnam_custom_device_mode_selector.append_text(*i);
407         }
408
409         _midnam_custom_device_mode_selector.set_active(0);
410         
411         _route->instrument_info().set_external_instrument (
412                 _midnam_model_selector.get_active_text(),
413                 _midnam_custom_device_mode_selector.get_active_text());
414
415         // Rebuild controller menu
416         _controller_menu_map.clear ();
417         delete controller_menu;
418         controller_menu = 0;
419         build_automation_action_menu(false);
420 }
421
422 void
423 MidiTimeAxisView::custom_device_mode_changed()
424 {
425         const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
426         set_gui_property (X_("midnam-custom-device-mode"), mode);
427         _route->instrument_info().set_external_instrument (
428                 _midnam_model_selector.get_active_text(), mode);
429 }
430
431 MidiStreamView*
432 MidiTimeAxisView::midi_view()
433 {
434         return dynamic_cast<MidiStreamView*>(_view);
435 }
436
437 void
438 MidiTimeAxisView::set_height (uint32_t h)
439 {
440         if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
441                 _midi_controls_box.show ();
442         } else {
443                 _midi_controls_box.hide();
444         }
445         
446         if (h >= KEYBOARD_MIN_HEIGHT) {
447                 if (is_track() && _range_scroomer) {
448                         _range_scroomer->show();
449                 }
450                 if (is_track() && _piano_roll_header) {
451                         _piano_roll_header->show();
452                 }
453         } else {
454                 if (is_track() && _range_scroomer) {
455                         _range_scroomer->hide();
456                 }
457                 if (is_track() && _piano_roll_header) {
458                         _piano_roll_header->hide();
459                 }
460         }
461
462         /* We need to do this after changing visibility of our stuff, as it will
463            eventually trigger a call to Editor::reset_controls_layout_width(),
464            which needs to know if we have just shown or hidden a scroomer /
465            piano roll.
466         */
467         RouteTimeAxisView::set_height (h);
468 }
469
470 void
471 MidiTimeAxisView::append_extra_display_menu_items ()
472 {
473         using namespace Menu_Helpers;
474
475         MenuList& items = display_menu->items();
476
477         // Note range
478         Menu *range_menu = manage(new Menu);
479         MenuList& range_items = range_menu->items();
480         range_menu->set_name ("ArdourContextMenu");
481
482         range_items.push_back (
483                 MenuElem (_("Show Full Range"),
484                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range), 
485                                       MidiStreamView::FullRange, true)));
486
487         range_items.push_back (
488                 MenuElem (_("Fit Contents"),
489                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
490                                       MidiStreamView::ContentsRange, true)));
491
492         items.push_back (MenuElem (_("Note Range"), *range_menu));
493         items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
494         items.push_back (MenuElem (_("Channel Selector"),
495                                    sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
496
497         color_mode_menu = build_color_mode_menu();
498         if (color_mode_menu) {
499                 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
500         }
501         
502         items.push_back (SeparatorElem ());
503 }
504
505 void
506 MidiTimeAxisView::toggle_channel_selector ()
507 {
508         if (!_channel_selector) {
509                 _channel_selector = new MidiChannelSelectorWindow (midi_track());
510
511                 if (_color_mode == ChannelColors) {
512                         _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
513                 } else {
514                         _channel_selector->set_default_channel_color ();
515                 }
516
517                 _channel_selector->set_position (WIN_POS_MOUSE);
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(CanvasNoteEvent::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 }