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