commit immediately post linking
[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);
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->set_position (WIN_POS_MOUSE);
519                 _channel_selector->show_all ();
520         } else {
521                 _channel_selector->cycle_visibility ();
522         }
523 }
524
525 void
526 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
527 {
528         using namespace Menu_Helpers;
529
530         /* If we have a controller menu, we need to detach it before
531            RouteTimeAxis::build_automation_action_menu destroys the
532            menu it is attached to.  Otherwise GTK destroys
533            controller_menu's gobj, meaning that it can't be reattached
534            below.  See bug #3134.
535         */
536
537         if (controller_menu) {
538                 detach_menu (*controller_menu);
539         }
540
541         _channel_command_menu_map.clear ();
542         RouteTimeAxisView::build_automation_action_menu (for_selection);
543
544         MenuList& automation_items = automation_action_menu->items();
545
546         uint16_t selected_channels = midi_track()->get_playback_channel_mask();
547
548         if (selected_channels !=  0) {
549
550                 automation_items.push_back (SeparatorElem());
551
552                 /* these 2 MIDI "command" types are semantically more like automation
553                    than note data, but they are not MIDI controllers. We give them
554                    special status in this menu, since they will not show up in the
555                    controller list and anyone who actually knows something about MIDI
556                    (!) would not expect to find them there.
557                 */
558
559                 add_channel_command_menu_item (
560                         automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
561                 automation_items.back().set_sensitive (
562                         !for_selection || _editor.get_selection().tracks.size() == 1);
563                 add_channel_command_menu_item (
564                         automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
565                 automation_items.back().set_sensitive (
566                         !for_selection || _editor.get_selection().tracks.size() == 1);
567
568                 /* now all MIDI controllers. Always offer the possibility that we will
569                    rebuild the controllers menu since it might need to be updated after
570                    a channel mode change or other change. Also detach it first in case
571                    it has been used anywhere else.
572                 */
573
574                 build_controller_menu ();
575
576                 automation_items.push_back (SeparatorElem());
577                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
578                 automation_items.back().set_sensitive (
579                         !for_selection || _editor.get_selection().tracks.size() == 1);
580         } else {
581                 automation_items.push_back (
582                         MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
583                 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
584         }
585 }
586
587 void
588 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
589 {
590         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
591
592         for (uint8_t chn = 0; chn < 16; chn++) {
593                 if (selected_channels & (0x0001 << chn)) {
594
595                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
596                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
597
598                         if (menu) {
599                                 menu->set_active (yn);
600                         }
601                 }
602         }
603 }
604
605 void
606 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
607                                                  const string&           label,
608                                                  AutomationType          auto_type,
609                                                  uint8_t                 cmd)
610 {
611         using namespace Menu_Helpers;
612
613         /* count the number of selected channels because we will build a different menu
614            structure if there is more than 1 selected.
615          */
616
617         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
618         int chn_cnt = 0;
619
620         for (uint8_t chn = 0; chn < 16; chn++) {
621                 if (selected_channels & (0x0001 << chn)) {
622                         if (++chn_cnt > 1) {
623                                 break;
624                         }
625                 }
626         }
627
628         if (chn_cnt > 1) {
629
630                 /* multiple channels - create a submenu, with 1 item per channel */
631
632                 Menu* chn_menu = manage (new Menu);
633                 MenuList& chn_items (chn_menu->items());
634                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
635
636                 /* add a couple of items to hide/show all of them */
637
638                 chn_items.push_back (
639                         MenuElem (_("Hide all channels"),
640                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
641                                               false, param_without_channel)));
642                 chn_items.push_back (
643                         MenuElem (_("Show all channels"),
644                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
645                                               true, param_without_channel)));
646
647                 for (uint8_t chn = 0; chn < 16; chn++) {
648                         if (selected_channels & (0x0001 << chn)) {
649
650                                 /* for each selected channel, add a menu item for this controller */
651
652                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
653                                 chn_items.push_back (
654                                         CheckMenuElem (string_compose (_("Channel %1"), chn+1),
655                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
656                                                                    fully_qualified_param)));
657
658                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
659                                 bool visible = false;
660
661                                 if (track) {
662                                         if (track->marked_for_display()) {
663                                                 visible = true;
664                                         }
665                                 }
666
667                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
668                                 _channel_command_menu_map[fully_qualified_param] = cmi;
669                                 cmi->set_active (visible);
670                         }
671                 }
672
673                 /* now create an item in the parent menu that has the per-channel list as a submenu */
674
675                 items.push_back (MenuElem (label, *chn_menu));
676
677         } else {
678
679                 /* just one channel - create a single menu item for this command+channel combination*/
680
681                 for (uint8_t chn = 0; chn < 16; chn++) {
682                         if (selected_channels & (0x0001 << chn)) {
683
684                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
685                                 items.push_back (
686                                         CheckMenuElem (label,
687                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
688                                                                    fully_qualified_param)));
689
690                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
691                                 bool visible = false;
692
693                                 if (track) {
694                                         if (track->marked_for_display()) {
695                                                 visible = true;
696                                         }
697                                 }
698
699                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
700                                 _channel_command_menu_map[fully_qualified_param] = cmi;
701                                 cmi->set_active (visible);
702
703                                 /* one channel only */
704                                 break;
705                         }
706                 }
707         }
708 }
709
710 /** Add a single menu item for a controller on one channel. */
711 void
712 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
713                                                      int                     ctl,
714                                                      const std::string&      name)
715 {
716         using namespace Menu_Helpers;
717
718         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
719         for (uint8_t chn = 0; chn < 16; chn++) {
720                 if (selected_channels & (0x0001 << chn)) {
721
722                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
723                         ctl_items.push_back (
724                                 CheckMenuElem (
725                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn)),
726                                         sigc::bind (
727                                                 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
728                                                 fully_qualified_param)));
729                         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
730
731                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
732                                 fully_qualified_param);
733
734                         bool visible = false;
735                         if (track) {
736                                 if (track->marked_for_display()) {
737                                         visible = true;
738                                 }
739                         }
740
741                         CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
742                         _controller_menu_map[fully_qualified_param] = cmi;
743                         cmi->set_active (visible);
744
745                         /* one channel only */
746                         break;
747                 }
748         }
749 }
750
751 /** Add a submenu with 1 item per channel for a controller on many channels. */
752 void
753 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
754                                                     int                     ctl,
755                                                     const std::string&      name)
756 {
757         using namespace Menu_Helpers;
758
759         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
760
761         Menu* chn_menu = manage (new Menu);
762         MenuList& chn_items (chn_menu->items());
763
764         /* add a couple of items to hide/show this controller on all channels */
765
766         Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
767         chn_items.push_back (
768                 MenuElem (_("Hide all channels"),
769                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
770                                       false, param_without_channel)));
771         chn_items.push_back (
772                 MenuElem (_("Show all channels"),
773                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
774                                       true, param_without_channel)));
775
776         for (uint8_t chn = 0; chn < 16; chn++) {
777                 if (selected_channels & (0x0001 << chn)) {
778
779                         /* for each selected channel, add a menu item for this controller */
780
781                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
782                         chn_items.push_back (
783                                 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
784                                                sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
785                                                            fully_qualified_param)));
786
787                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
788                                 fully_qualified_param);
789                         bool visible = false;
790
791                         if (track) {
792                                 if (track->marked_for_display()) {
793                                         visible = true;
794                                 }
795                         }
796
797                         CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
798                         _controller_menu_map[fully_qualified_param] = cmi;
799                         cmi->set_active (visible);
800                 }
801         }
802
803         /* add the per-channel menu to the list of controllers, with the name of the controller */
804         ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
805                                        *chn_menu));
806         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
807 }
808
809 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
810 MidiTimeAxisView::get_device_mode()
811 {
812         using namespace MIDI::Name;
813
814         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
815         if (!device_names) {
816                 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
817         }
818
819         return device_names->custom_device_mode_by_name(
820                 gui_property (X_("midnam-custom-device-mode")));
821 }
822
823 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
824 MidiTimeAxisView::get_device_names()
825 {
826         using namespace MIDI::Name;
827
828         const std::string model = gui_property (X_("midnam-model-name"));
829
830         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
831                 .document_by_model(model);
832         if (midnam) {
833                 return midnam->master_device_names(model);
834         } else {
835                 return boost::shared_ptr<MasterDeviceNames>();
836         }
837 }
838
839 void
840 MidiTimeAxisView::build_controller_menu ()
841 {
842         using namespace Menu_Helpers;
843
844         if (controller_menu) {
845                 /* it exists and has not been invalidated by a channel mode change */
846                 return;
847         }
848
849         controller_menu = new Menu; // explicitly managed by us
850         MenuList& items (controller_menu->items());
851
852         /* create several "top level" menu items for sets of controllers (16 at a
853            time), and populate each one with a submenu for each controller+channel
854            combination covering the currently selected channels for this track
855         */
856
857         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
858
859         /* count the number of selected channels because we will build a different menu
860            structure if there is more than 1 selected.
861         */
862
863         int chn_cnt = 0;
864         for (uint8_t chn = 0; chn < 16; chn++) {
865                 if (selected_channels & (0x0001 << chn)) {
866                         if (++chn_cnt > 1) {
867                                 break;
868                         }
869                 }
870         }
871
872         using namespace MIDI::Name;
873         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
874
875         if (device_names && !device_names->controls().empty()) {
876                 /* Controllers names available in midnam file, generate fancy menu */
877                 unsigned n_items  = 0;
878                 unsigned n_groups = 0;
879
880                 /* TODO: This is not correct, should look up the currently applicable ControlNameList
881                    and only build a menu for that one. */
882                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
883                      l != device_names->controls().end(); ++l) {
884                         boost::shared_ptr<ControlNameList> name_list = l->second;
885                         Menu*                              ctl_menu  = NULL;
886                         
887                         for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
888                              c != name_list->controls().end();) {
889                                 const uint16_t ctl = c->second->number();
890                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
891                                         /* Skip bank select controllers since they're handled specially */
892                                         if (n_items == 0) {
893                                                 /* Create a new submenu */
894                                                 ctl_menu = manage (new Menu);
895                                         }
896                                 
897                                         MenuList& ctl_items (ctl_menu->items());
898                                         if (chn_cnt > 1) {
899                                                 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
900                                         } else {
901                                                 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
902                                         }
903                                 }
904
905                                 ++c;
906                                 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
907                                         /* Submenu has 16 items or we're done, add it to controller menu and reset */
908                                         items.push_back(
909                                                 MenuElem(string_compose(_("Controllers %1-%2"),
910                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
911                                                          *ctl_menu));
912                                         ctl_menu = NULL;
913                                         n_items  = 0;
914                                         ++n_groups;
915                                 }
916                         }
917                 }
918         } else {
919                 /* No controllers names, generate generic numeric menu */
920                 for (int i = 0; i < 127; i += 16) {
921                         Menu*     ctl_menu = manage (new Menu);
922                         MenuList& ctl_items (ctl_menu->items());
923
924                         for (int ctl = i; ctl < i+16; ++ctl) {
925                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
926                                         /* Skip bank select controllers since they're handled specially */
927                                         continue;
928                                 }
929
930                                 if (chn_cnt > 1) {
931                                         add_multi_channel_controller_item(
932                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
933                                 } else {
934                                         add_single_channel_controller_item(
935                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
936                                 }
937                         }
938
939                         /* Add submenu for this block of controllers to controller menu */
940                         items.push_back (
941                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
942                                           *ctl_menu));
943                 }
944         }
945 }
946
947 Gtk::Menu*
948 MidiTimeAxisView::build_note_mode_menu()
949 {
950         using namespace Menu_Helpers;
951
952         Menu* mode_menu = manage (new Menu);
953         MenuList& items = mode_menu->items();
954         mode_menu->set_name ("ArdourContextMenu");
955
956         RadioMenuItem::Group mode_group;
957         items.push_back (
958                 RadioMenuElem (mode_group,_("Sustained"),
959                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
960                                            Sustained, true)));
961         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
962         _note_mode_item->set_active(_note_mode == Sustained);
963
964         items.push_back (
965                 RadioMenuElem (mode_group, _("Percussive"),
966                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
967                                            Percussive, true)));
968         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
969         _percussion_mode_item->set_active(_note_mode == Percussive);
970
971         return mode_menu;
972 }
973
974 Gtk::Menu*
975 MidiTimeAxisView::build_color_mode_menu()
976 {
977         using namespace Menu_Helpers;
978
979         Menu* mode_menu = manage (new Menu);
980         MenuList& items = mode_menu->items();
981         mode_menu->set_name ("ArdourContextMenu");
982
983         RadioMenuItem::Group mode_group;
984         items.push_back (
985                 RadioMenuElem (mode_group, _("Meter Colors"),
986                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
987                                            MeterColors, false, true, true)));
988         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
989         _meter_color_mode_item->set_active(_color_mode == MeterColors);
990
991         items.push_back (
992                 RadioMenuElem (mode_group, _("Channel Colors"),
993                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
994                                            ChannelColors, false, true, true)));
995         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
996         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
997
998         items.push_back (
999                 RadioMenuElem (mode_group, _("Track Color"),
1000                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1001                                            TrackColor, false, true, true)));
1002         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1003         _channel_color_mode_item->set_active(_color_mode == TrackColor);
1004
1005         return mode_menu;
1006 }
1007
1008 void
1009 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1010 {
1011         if (apply_to_selection) {
1012                 _editor.get_selection().tracks.foreach_midi_time_axis (
1013                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1014         } else {
1015                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1016                         _note_mode = mode;
1017                         midi_track()->set_note_mode(mode);
1018                         set_gui_property ("note-mode", enum_2_string(_note_mode));
1019                         _view->redisplay_track();
1020                 }
1021         }
1022 }
1023
1024 void
1025 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1026 {
1027         if (apply_to_selection) {
1028                 _editor.get_selection().tracks.foreach_midi_time_axis (
1029                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1030         } else {
1031                 if (_color_mode == mode && !force) {
1032                         return;
1033                 }
1034                 
1035                 if (_channel_selector) {
1036                         if (mode == ChannelColors) {
1037                                 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1038                         } else {
1039                                 _channel_selector->set_default_channel_color();
1040                         }
1041                 }
1042                 
1043                 _color_mode = mode;
1044                 set_gui_property ("color-mode", enum_2_string(_color_mode));
1045                 if (redisplay) {
1046                         _view->redisplay_track();
1047                 }
1048         }
1049 }
1050
1051 void
1052 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1053 {
1054         if (apply_to_selection) {
1055                 _editor.get_selection().tracks.foreach_midi_time_axis (
1056                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1057         } else {
1058                 if (!_ignore_signals) {
1059                         midi_view()->set_note_range(range);
1060                 }
1061         }
1062 }
1063
1064 void
1065 MidiTimeAxisView::update_range()
1066 {
1067         MidiGhostRegion* mgr;
1068
1069         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1070                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1071                         mgr->update_range();
1072                 }
1073         }
1074 }
1075
1076 void
1077 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1078 {
1079         if (apply_to_selection) {
1080                 _editor.get_selection().tracks.foreach_midi_time_axis (
1081                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1082         } else {
1083                 if (midi_track()) {
1084                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1085
1086                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1087                                 create_automation_child(*i, true);
1088                         }
1089                 }
1090
1091                 RouteTimeAxisView::show_all_automation ();
1092         }
1093 }
1094
1095 void
1096 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1097 {
1098         if (apply_to_selection) {
1099                 _editor.get_selection().tracks.foreach_midi_time_axis (
1100                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1101         } else {
1102                 if (midi_track()) {
1103                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1104
1105                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1106                                 create_automation_child (*i, true);
1107                         }
1108                 }
1109
1110                 RouteTimeAxisView::show_existing_automation ();
1111         }
1112 }
1113
1114 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1115  */
1116 void
1117 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1118 {
1119         if (param.type() == NullAutomation) {
1120                 return;
1121         }
1122
1123         AutomationTracks::iterator existing = _automation_tracks.find (param);
1124
1125         if (existing != _automation_tracks.end()) {
1126
1127                 /* automation track created because we had existing data for
1128                  * the processor, but visibility may need to be controlled
1129                  * since it will have been set visible by default.
1130                  */
1131
1132                 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1133                         request_redraw ();
1134                 }
1135
1136                 return;
1137         }
1138
1139         boost::shared_ptr<AutomationTimeAxisView> track;
1140
1141         switch (param.type()) {
1142
1143         case GainAutomation:
1144                 create_gain_automation_child (param, show);
1145                 break;
1146
1147         case PluginAutomation:
1148                 /* handled elsewhere */
1149                 break;
1150
1151         case MidiCCAutomation:
1152         case MidiPgmChangeAutomation:
1153         case MidiPitchBenderAutomation:
1154         case MidiChannelPressureAutomation:
1155         case MidiSystemExclusiveAutomation:
1156                 /* These controllers are region "automation" - they are owned
1157                  * by regions (and their MidiModels), not by the track. As a
1158                  * result we do not create an AutomationList/Line for the track
1159                  * ... except here we are doing something!! XXX 
1160                  */
1161
1162                 track.reset (new AutomationTimeAxisView (
1163                                      _session,
1164                                      _route,
1165                                      boost::shared_ptr<Automatable> (),
1166                                      boost::shared_ptr<AutomationControl> (),
1167                                      param,
1168                                      _editor,
1169                                      *this,
1170                                      true,
1171                                      parent_canvas,
1172                                      _route->describe_parameter(param)));
1173
1174                 if (_view) {
1175                         _view->foreach_regionview (
1176                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1177                 }
1178
1179                 add_automation_child (param, track, show);
1180                 break;
1181
1182         default:
1183                 error << "MidiTimeAxisView: unknown automation child "
1184                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1185         }
1186 }
1187
1188 void
1189 MidiTimeAxisView::route_active_changed ()
1190 {
1191         RouteUI::route_active_changed ();
1192
1193         if (is_track()) {
1194                 if (_route->active()) {
1195                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1196                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1197                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1198                 } else {
1199                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1200                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1201                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1202                 }
1203         } else {
1204                 if (_route->active()) {
1205                         controls_ebox.set_name ("BusControlsBaseUnselected");
1206                         controls_base_selected_name = "BusControlsBaseSelected";
1207                         controls_base_unselected_name = "BusControlsBaseUnselected";
1208                 } else {
1209                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1210                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1211                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1212                 }
1213         }
1214 }
1215
1216 void
1217 MidiTimeAxisView::set_note_selection (uint8_t note)
1218 {
1219         if (!_editor.internal_editing()) {
1220                 return;
1221         }
1222
1223         uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1224
1225         if (_view->num_selected_regionviews() == 0) {
1226                 _view->foreach_regionview (
1227                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1228                                     note, chn_mask));
1229         } else {
1230                 _view->foreach_selected_regionview (
1231                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1232                                     note, chn_mask));
1233         }
1234 }
1235
1236 void
1237 MidiTimeAxisView::add_note_selection (uint8_t note)
1238 {
1239         if (!_editor.internal_editing()) {
1240                 return;
1241         }
1242
1243         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1244
1245         if (_view->num_selected_regionviews() == 0) {
1246                 _view->foreach_regionview (
1247                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1248                                     note, chn_mask));
1249         } else {
1250                 _view->foreach_selected_regionview (
1251                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1252                                     note, chn_mask));
1253         }
1254 }
1255
1256 void
1257 MidiTimeAxisView::extend_note_selection (uint8_t note)
1258 {
1259         if (!_editor.internal_editing()) {
1260                 return;
1261         }
1262
1263         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1264
1265         if (_view->num_selected_regionviews() == 0) {
1266                 _view->foreach_regionview (
1267                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1268                                     note, chn_mask));
1269         } else {
1270                 _view->foreach_selected_regionview (
1271                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1272                                     note, chn_mask));
1273         }
1274 }
1275
1276 void
1277 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1278 {
1279         if (!_editor.internal_editing()) {
1280                 return;
1281         }
1282
1283         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1284
1285         if (_view->num_selected_regionviews() == 0) {
1286                 _view->foreach_regionview (
1287                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1288                                     note, chn_mask));
1289         } else {
1290                 _view->foreach_selected_regionview (
1291                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1292                                     note, chn_mask));
1293         }
1294 }
1295
1296 void
1297 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1298 {
1299         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1300 }
1301
1302 void
1303 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1304 {
1305         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1306 }
1307
1308 void
1309 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1310 {
1311         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1312 }
1313
1314 void
1315 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1316 {
1317         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1318 }
1319
1320 void
1321 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1322 {
1323         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1324            the right ones.
1325         */
1326
1327         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1328         bool changed = false;
1329
1330         no_redraw = true;
1331
1332         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1333
1334                 for (uint32_t chn = 0; chn < 16; ++chn) {
1335                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1336                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1337
1338                         if (!track) {
1339                                 continue;
1340                         }
1341
1342                         if ((selected_channels & (0x0001 << chn)) == 0) {
1343                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1344                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1345                                 */
1346                                 changed = track->set_marked_for_display (false) || changed;
1347                         } else {
1348                                 changed = track->set_marked_for_display (true) || changed;
1349                         }
1350                 }
1351         }
1352
1353         no_redraw = false;
1354
1355         /* TODO: Bender, Pressure */
1356
1357         /* invalidate the controller menu, so that we rebuild it next time */
1358         _controller_menu_map.clear ();
1359         delete controller_menu;
1360         controller_menu = 0;
1361
1362         if (changed) {
1363                 request_redraw ();
1364         }
1365 }
1366
1367 Gtk::CheckMenuItem*
1368 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1369 {
1370         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1371         if (m) {
1372                 return m;
1373         }
1374
1375         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1376         if (i != _controller_menu_map.end()) {
1377                 return i->second;
1378         }
1379
1380         i = _channel_command_menu_map.find (param);
1381         if (i != _channel_command_menu_map.end()) {
1382                 return i->second;
1383         }
1384
1385         return 0;
1386 }
1387
1388 boost::shared_ptr<MidiRegion>
1389 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1390 {
1391         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1392
1393         real_editor->begin_reversible_command (Operations::create_region);
1394         playlist()->clear_changes ();
1395
1396         real_editor->snap_to (pos, 0);
1397
1398         boost::shared_ptr<Source> src = _session->create_midi_source_for_session (
1399                 view()->trackview().track().get(), view()->trackview().track()->name());
1400         PropertyList plist;
1401
1402         plist.add (ARDOUR::Properties::start, 0);
1403         plist.add (ARDOUR::Properties::length, length);
1404         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1405
1406         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1407
1408         playlist()->add_region (region, pos);
1409         _session->add_command (new StatefulDiffCommand (playlist()));
1410
1411         if (commit) {
1412                 real_editor->commit_reversible_command ();
1413         }
1414
1415         return boost::dynamic_pointer_cast<MidiRegion>(region);
1416 }
1417
1418 void
1419 MidiTimeAxisView::ensure_step_editor ()
1420 {
1421         if (!_step_editor) {
1422                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1423         }
1424 }
1425
1426 void
1427 MidiTimeAxisView::start_step_editing ()
1428 {
1429         ensure_step_editor ();
1430         _step_editor->start_step_editing ();
1431
1432 }
1433 void
1434 MidiTimeAxisView::stop_step_editing ()
1435 {
1436         if (_step_editor) {
1437                 _step_editor->stop_step_editing ();
1438         }
1439 }
1440
1441 /** @return channel (counted from 0) to add an event to, based on the current setting
1442  *  of the channel selector.
1443  */
1444 uint8_t
1445 MidiTimeAxisView::get_channel_for_add () const
1446 {
1447         uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1448         int chn_cnt = 0;
1449         uint8_t channel = 0;
1450
1451         /* pick the highest selected channel, unless all channels are selected,
1452            which is interpreted to mean channel 1 (zero)
1453         */
1454
1455         for (uint16_t i = 0; i < 16; ++i) {
1456                 if (chn_mask & (1<<i)) {
1457                         channel = i;
1458                         chn_cnt++;
1459                 }
1460         }
1461
1462         if (chn_cnt == 16) {
1463                 channel = 0;
1464         }
1465
1466         return channel;
1467 }
1468
1469 void
1470 MidiTimeAxisView::note_range_changed ()
1471 {
1472         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1473         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1474 }
1475
1476 void
1477 MidiTimeAxisView::contents_height_changed ()
1478 {
1479         _range_scroomer->set_size_request (-1, _view->child_height ());
1480 }
1481
1482 void
1483 MidiTimeAxisView::playback_channel_mode_changed ()
1484 {
1485         switch (midi_track()->get_playback_channel_mode()) {
1486         case AllChannels:
1487                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), ("all")));
1488                 break;
1489         case FilterChannels:
1490                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), ("some")));
1491                 break;
1492         case ForceChannel:
1493                 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), ("all"), ffs (midi_track()->get_playback_channel_mask())));
1494                 break;
1495         }
1496 }
1497
1498 void
1499 MidiTimeAxisView::capture_channel_mode_changed ()
1500 {
1501         switch (midi_track()->get_capture_channel_mode()) {
1502         case AllChannels:
1503                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), ("all")));
1504                 break;
1505         case FilterChannels:
1506                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), ("some")));
1507                 break;
1508         case ForceChannel:
1509                 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), ("all"), ffs (midi_track()->get_capture_channel_mask())));
1510                 break;
1511         }
1512 }