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