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