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