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