3627074bc89df026bf4900a6b4caf14433a9b168
[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 (&MidiTimeAxisView::reread_midnam, this),
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::reread_midnam ()
450 {
451         boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
452         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
453         pi->plugin ()->read_midnam();
454
455         if (_patch_change_dialog) {
456                 _patch_change_dialog->refresh ();
457         }
458 }
459 void
460 MidiTimeAxisView::model_changed(const std::string& model)
461 {
462         set_gui_property (X_("midnam-model-name"), model);
463
464         const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
465                 .custom_device_mode_names_by_model(model);
466
467         _midnam_model_selector.set_text(model);
468         _midnam_custom_device_mode_selector.clear_items();
469
470         for (std::list<std::string>::const_iterator i = device_modes.begin();
471              i != device_modes.end(); ++i) {
472                 _midnam_custom_device_mode_selector.AddMenuElem(
473                         Gtk::Menu_Helpers::MenuElem(
474                                 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
475                                                *i)));
476         }
477
478         if (!device_modes.empty()) {
479                 custom_device_mode_changed(device_modes.front());
480         }
481
482         if (device_modes.size() > 1) {
483                 _midnam_custom_device_mode_selector.show();
484         } else {
485                 _midnam_custom_device_mode_selector.hide();
486         }
487
488         // now this is a real bad hack
489         if (device_modes.size() > 0) {
490                 _route->instrument_info().set_external_instrument (model, device_modes.front());
491         } else {
492                 _route->instrument_info().set_external_instrument (model, "");
493         }
494
495         // Rebuild controller menu
496         _controller_menu_map.clear ();
497         delete controller_menu;
498         controller_menu = 0;
499         build_automation_action_menu(false);
500
501         if (_patch_change_dialog) {
502                 _patch_change_dialog->refresh ();
503         }
504 }
505
506 void
507 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
508 {
509         const std::string model = gui_property (X_("midnam-model-name"));
510
511         set_gui_property (X_("midnam-custom-device-mode"), mode);
512         _midnam_custom_device_mode_selector.set_text(mode);
513         _route->instrument_info().set_external_instrument (model, mode);
514 }
515
516 MidiStreamView*
517 MidiTimeAxisView::midi_view()
518 {
519         return dynamic_cast<MidiStreamView*>(_view);
520 }
521
522 void
523 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
524 {
525         if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
526                 _midi_controls_box.show ();
527         } else {
528                 _midi_controls_box.hide();
529         }
530
531         if (h >= KEYBOARD_MIN_HEIGHT) {
532                 if (is_track() && _range_scroomer) {
533                         _range_scroomer->show();
534                 }
535                 if (is_track() && _piano_roll_header) {
536                         _piano_roll_header->show();
537                 }
538         } else {
539                 if (is_track() && _range_scroomer) {
540                         _range_scroomer->hide();
541                 }
542                 if (is_track() && _piano_roll_header) {
543                         _piano_roll_header->hide();
544                 }
545         }
546
547         /* We need to do this after changing visibility of our stuff, as it will
548            eventually trigger a call to Editor::reset_controls_layout_width(),
549            which needs to know if we have just shown or hidden a scroomer /
550            piano roll.
551         */
552         RouteTimeAxisView::set_height (h, m);
553 }
554
555 void
556 MidiTimeAxisView::append_extra_display_menu_items ()
557 {
558         using namespace Menu_Helpers;
559
560         MenuList& items = display_menu->items();
561
562         // Note range
563         Menu *range_menu = manage(new Menu);
564         MenuList& range_items = range_menu->items();
565         range_menu->set_name ("ArdourContextMenu");
566
567         range_items.push_back (
568                 MenuElem (_("Show Full Range"),
569                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
570                                       MidiStreamView::FullRange, true)));
571
572         range_items.push_back (
573                 MenuElem (_("Fit Contents"),
574                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
575                                       MidiStreamView::ContentsRange, true)));
576
577         items.push_back (MenuElem (_("Note Range"), *range_menu));
578         items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
579         items.push_back (MenuElem (_("Channel Selector..."),
580                                    sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
581
582         items.push_back (MenuElem (_("Patch Selector..."),
583                                 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
584
585         color_mode_menu = build_color_mode_menu();
586         if (color_mode_menu) {
587                 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
588         }
589
590         items.push_back (SeparatorElem ());
591 }
592
593 void
594 MidiTimeAxisView::toggle_channel_selector ()
595 {
596         if (!_channel_selector) {
597                 _channel_selector = new MidiChannelSelectorWindow (midi_track());
598
599                 if (_color_mode == ChannelColors) {
600                         _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
601                 } else {
602                         _channel_selector->set_default_channel_color ();
603                 }
604
605                 _channel_selector->show_all ();
606         } else {
607                 _channel_selector->cycle_visibility ();
608         }
609 }
610
611 void
612 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
613 {
614         using namespace Menu_Helpers;
615
616         /* If we have a controller menu, we need to detach it before
617            RouteTimeAxis::build_automation_action_menu destroys the
618            menu it is attached to.  Otherwise GTK destroys
619            controller_menu's gobj, meaning that it can't be reattached
620            below.  See bug #3134.
621         */
622
623         if (controller_menu) {
624                 detach_menu (*controller_menu);
625         }
626
627         _channel_command_menu_map.clear ();
628         RouteTimeAxisView::build_automation_action_menu (for_selection);
629
630         MenuList& automation_items = automation_action_menu->items();
631
632         uint16_t selected_channels = midi_track()->get_playback_channel_mask();
633
634         if (selected_channels !=  0) {
635
636                 automation_items.push_back (SeparatorElem());
637
638                 /* these 2 MIDI "command" types are semantically more like automation
639                    than note data, but they are not MIDI controllers. We give them
640                    special status in this menu, since they will not show up in the
641                    controller list and anyone who actually knows something about MIDI
642                    (!) would not expect to find them there.
643                 */
644
645                 add_channel_command_menu_item (
646                         automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
647                 automation_items.back().set_sensitive (
648                         !for_selection || _editor.get_selection().tracks.size() == 1);
649                 add_channel_command_menu_item (
650                         automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
651                 automation_items.back().set_sensitive (
652                         !for_selection || _editor.get_selection().tracks.size() == 1);
653
654                 /* now all MIDI controllers. Always offer the possibility that we will
655                    rebuild the controllers menu since it might need to be updated after
656                    a channel mode change or other change. Also detach it first in case
657                    it has been used anywhere else.
658                 */
659
660                 build_controller_menu ();
661
662                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
663
664                 if (!poly_pressure_menu) {
665                         poly_pressure_menu = new Gtk::Menu;
666                 }
667
668                 automation_items.push_back (MenuElem  (_("Polyphonic Pressure"), *poly_pressure_menu));
669
670                 automation_items.back().set_sensitive (
671                         !for_selection || _editor.get_selection().tracks.size() == 1);
672         } else {
673                 automation_items.push_back (
674                         MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
675                 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
676         }
677 }
678
679 void
680 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
681 {
682         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
683
684         for (uint8_t chn = 0; chn < 16; chn++) {
685                 if (selected_channels & (0x0001 << chn)) {
686
687                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
688                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
689
690                         if (menu) {
691                                 menu->set_active (yn);
692                         }
693                 }
694         }
695 }
696
697 void
698 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
699                                                  const string&           label,
700                                                  AutomationType          auto_type,
701                                                  uint8_t                 cmd)
702 {
703         using namespace Menu_Helpers;
704
705         /* count the number of selected channels because we will build a different menu
706            structure if there is more than 1 selected.
707          */
708
709         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
710         int chn_cnt = 0;
711
712         for (uint8_t chn = 0; chn < 16; chn++) {
713                 if (selected_channels & (0x0001 << chn)) {
714                         if (++chn_cnt > 1) {
715                                 break;
716                         }
717                 }
718         }
719
720         if (chn_cnt > 1) {
721
722                 /* multiple channels - create a submenu, with 1 item per channel */
723
724                 Menu* chn_menu = manage (new Menu);
725                 MenuList& chn_items (chn_menu->items());
726                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
727
728                 /* add a couple of items to hide/show all of them */
729
730                 chn_items.push_back (
731                         MenuElem (_("Hide all channels"),
732                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
733                                               false, param_without_channel)));
734                 chn_items.push_back (
735                         MenuElem (_("Show all channels"),
736                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
737                                               true, param_without_channel)));
738
739                 for (uint8_t chn = 0; chn < 16; chn++) {
740                         if (selected_channels & (0x0001 << chn)) {
741
742                                 /* for each selected channel, add a menu item for this controller */
743
744                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
745                                 chn_items.push_back (
746                                         CheckMenuElem (string_compose (_("Channel %1"), chn+1),
747                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
748                                                                    fully_qualified_param)));
749
750                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
751                                 bool visible = false;
752
753                                 if (track) {
754                                         if (track->marked_for_display()) {
755                                                 visible = true;
756                                         }
757                                 }
758
759                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
760                                 _channel_command_menu_map[fully_qualified_param] = cmi;
761                                 cmi->set_active (visible);
762                         }
763                 }
764
765                 /* now create an item in the parent menu that has the per-channel list as a submenu */
766
767                 items.push_back (MenuElem (label, *chn_menu));
768
769         } else {
770
771                 /* just one channel - create a single menu item for this command+channel combination*/
772
773                 for (uint8_t chn = 0; chn < 16; chn++) {
774                         if (selected_channels & (0x0001 << chn)) {
775
776                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
777                                 items.push_back (
778                                         CheckMenuElem (label,
779                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
780                                                                    fully_qualified_param)));
781
782                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
783                                 bool visible = false;
784
785                                 if (track) {
786                                         if (track->marked_for_display()) {
787                                                 visible = true;
788                                         }
789                                 }
790
791                                 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
792                                 _channel_command_menu_map[fully_qualified_param] = cmi;
793                                 cmi->set_active (visible);
794
795                                 /* one channel only */
796                                 break;
797                         }
798                 }
799         }
800 }
801
802 /** Add a single menu item for a controller on one channel. */
803 void
804 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
805                                                      int                     ctl,
806                                                      const std::string&      name)
807 {
808         using namespace Menu_Helpers;
809
810         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
811         for (uint8_t chn = 0; chn < 16; chn++) {
812                 if (selected_channels & (0x0001 << chn)) {
813
814                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
815                         ctl_items.push_back (
816                                 CheckMenuElem (
817                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
818                                         sigc::bind (
819                                                 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
820                                                 fully_qualified_param)));
821                         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
822
823                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
824                                 fully_qualified_param);
825
826                         bool visible = false;
827                         if (track) {
828                                 if (track->marked_for_display()) {
829                                         visible = true;
830                                 }
831                         }
832
833                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
834                         _controller_menu_map[fully_qualified_param] = cmi;
835                         cmi->set_active (visible);
836
837                         /* one channel only */
838                         break;
839                 }
840         }
841 }
842
843 /** Add a submenu with 1 item per channel for a controller on many channels. */
844 void
845 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
846                                                     int                     ctl,
847                                                     const std::string&      name)
848 {
849         using namespace Menu_Helpers;
850
851         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
852
853         Menu* chn_menu = manage (new Menu);
854         MenuList& chn_items (chn_menu->items());
855
856         /* add a couple of items to hide/show this controller on all channels */
857
858         Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
859         chn_items.push_back (
860                 MenuElem (_("Hide all channels"),
861                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
862                                       false, param_without_channel)));
863         chn_items.push_back (
864                 MenuElem (_("Show all channels"),
865                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
866                                       true, param_without_channel)));
867
868         for (uint8_t chn = 0; chn < 16; chn++) {
869                 if (selected_channels & (0x0001 << chn)) {
870
871                         /* for each selected channel, add a menu item for this controller */
872
873                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
874                         chn_items.push_back (
875                                 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
876                                                sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
877                                                            fully_qualified_param)));
878
879                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
880                                 fully_qualified_param);
881                         bool visible = false;
882
883                         if (track) {
884                                 if (track->marked_for_display()) {
885                                         visible = true;
886                                 }
887                         }
888
889                         Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
890                         _controller_menu_map[fully_qualified_param] = cmi;
891                         cmi->set_active (visible);
892                 }
893         }
894
895         /* add the per-channel menu to the list of controllers, with the name of the controller */
896         ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
897                                        *chn_menu));
898         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
899 }
900
901 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
902 MidiTimeAxisView::get_device_mode()
903 {
904         using namespace MIDI::Name;
905
906         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
907         if (!device_names) {
908                 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
909         }
910
911         return device_names->custom_device_mode_by_name(
912                 gui_property (X_("midnam-custom-device-mode")));
913 }
914
915 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
916 MidiTimeAxisView::get_device_names()
917 {
918         using namespace MIDI::Name;
919
920         const std::string model = gui_property (X_("midnam-model-name"));
921
922         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
923                 .document_by_model(model);
924         if (midnam) {
925                 return midnam->master_device_names(model);
926         } else {
927                 return boost::shared_ptr<MasterDeviceNames>();
928         }
929 }
930
931 void
932 MidiTimeAxisView::build_controller_menu ()
933 {
934         using namespace Menu_Helpers;
935
936         if (controller_menu) {
937                 /* it exists and has not been invalidated by a channel mode change */
938                 return;
939         }
940
941         controller_menu = new Menu; // explicitly managed by us
942         MenuList& items (controller_menu->items());
943
944         /* create several "top level" menu items for sets of controllers (16 at a
945            time), and populate each one with a submenu for each controller+channel
946            combination covering the currently selected channels for this track
947         */
948
949         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
950
951         /* count the number of selected channels because we will build a different menu
952            structure if there is more than 1 selected.
953         */
954
955         int chn_cnt = 0;
956         for (uint8_t chn = 0; chn < 16; chn++) {
957                 if (selected_channels & (0x0001 << chn)) {
958                         if (++chn_cnt > 1) {
959                                 break;
960                         }
961                 }
962         }
963
964         using namespace MIDI::Name;
965         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
966
967         if (device_names && !device_names->controls().empty()) {
968                 /* Controllers names available in midnam file, generate fancy menu */
969                 unsigned n_items  = 0;
970                 unsigned n_groups = 0;
971
972                 /* TODO: This is not correct, should look up the currently applicable ControlNameList
973                    and only build a menu for that one. */
974                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
975                      l != device_names->controls().end(); ++l) {
976                         boost::shared_ptr<ControlNameList> name_list = l->second;
977                         Menu*                              ctl_menu  = NULL;
978
979                         for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
980                              c != name_list->controls().end();) {
981                                 const uint16_t ctl = c->second->number();
982                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
983                                         /* Skip bank select controllers since they're handled specially */
984                                         if (n_items == 0) {
985                                                 /* Create a new submenu */
986                                                 ctl_menu = manage (new Menu);
987                                         }
988
989                                         MenuList& ctl_items (ctl_menu->items());
990                                         if (chn_cnt > 1) {
991                                                 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
992                                         } else {
993                                                 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
994                                         }
995                                 }
996
997                                 ++c;
998                                 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
999                                         /* Submenu has 16 items or we're done, add it to controller menu and reset */
1000                                         items.push_back(
1001                                                 MenuElem(string_compose(_("Controllers %1-%2"),
1002                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
1003                                                          *ctl_menu));
1004                                         ctl_menu = NULL;
1005                                         n_items  = 0;
1006                                         ++n_groups;
1007                                 }
1008                         }
1009                 }
1010         } else {
1011                 /* No controllers names, generate generic numeric menu */
1012                 for (int i = 0; i < 127; i += 16) {
1013                         Menu*     ctl_menu = manage (new Menu);
1014                         MenuList& ctl_items (ctl_menu->items());
1015
1016                         for (int ctl = i; ctl < i+16; ++ctl) {
1017                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1018                                         /* Skip bank select controllers since they're handled specially */
1019                                         continue;
1020                                 }
1021
1022                                 if (chn_cnt > 1) {
1023                                         add_multi_channel_controller_item(
1024                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1025                                 } else {
1026                                         add_single_channel_controller_item(
1027                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1028                                 }
1029                         }
1030
1031                         /* Add submenu for this block of controllers to controller menu */
1032                         items.push_back (
1033                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1034                                           *ctl_menu));
1035                 }
1036         }
1037 }
1038
1039 Gtk::Menu*
1040 MidiTimeAxisView::build_note_mode_menu()
1041 {
1042         using namespace Menu_Helpers;
1043
1044         Menu* mode_menu = manage (new Menu);
1045         MenuList& items = mode_menu->items();
1046         mode_menu->set_name ("ArdourContextMenu");
1047
1048         RadioMenuItem::Group mode_group;
1049         items.push_back (
1050                 RadioMenuElem (mode_group,_("Sustained"),
1051                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1052                                            Sustained, true)));
1053         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1054         _note_mode_item->set_active(_note_mode == Sustained);
1055
1056         items.push_back (
1057                 RadioMenuElem (mode_group, _("Percussive"),
1058                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1059                                            Percussive, true)));
1060         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1061         _percussion_mode_item->set_active(_note_mode == Percussive);
1062
1063         return mode_menu;
1064 }
1065
1066 Gtk::Menu*
1067 MidiTimeAxisView::build_color_mode_menu()
1068 {
1069         using namespace Menu_Helpers;
1070
1071         Menu* mode_menu = manage (new Menu);
1072         MenuList& items = mode_menu->items();
1073         mode_menu->set_name ("ArdourContextMenu");
1074
1075         RadioMenuItem::Group mode_group;
1076         items.push_back (
1077                 RadioMenuElem (mode_group, _("Meter Colors"),
1078                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1079                                            MeterColors, false, true, true)));
1080         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1081         _meter_color_mode_item->set_active(_color_mode == MeterColors);
1082
1083         items.push_back (
1084                 RadioMenuElem (mode_group, _("Channel Colors"),
1085                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1086                                            ChannelColors, false, true, true)));
1087         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1088         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1089
1090         items.push_back (
1091                 RadioMenuElem (mode_group, _("Track Color"),
1092                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1093                                            TrackColor, false, true, true)));
1094         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1095         _channel_color_mode_item->set_active(_color_mode == TrackColor);
1096
1097         return mode_menu;
1098 }
1099
1100 void
1101 MidiTimeAxisView::send_patch_change ()
1102 {
1103         if (!_route) {
1104                 return;
1105         }
1106         if (_patch_change_dialog) {
1107                 _patch_change_dialog->present ();
1108                 return;
1109         }
1110
1111         PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1112         _patch_change_dialog = d;
1113         d->present ();
1114 }
1115
1116 void
1117 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1118 {
1119         if (apply_to_selection) {
1120                 _editor.get_selection().tracks.foreach_midi_time_axis (
1121                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1122         } else {
1123                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1124                         _note_mode = mode;
1125                         midi_track()->set_note_mode(mode);
1126                         set_gui_property ("note-mode", enum_2_string(_note_mode));
1127                         _view->redisplay_track();
1128                 }
1129         }
1130 }
1131
1132 void
1133 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1134 {
1135         if (apply_to_selection) {
1136                 _editor.get_selection().tracks.foreach_midi_time_axis (
1137                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1138         } else {
1139                 if (_color_mode == mode && !force) {
1140                         return;
1141                 }
1142
1143                 if (_channel_selector) {
1144                         if (mode == ChannelColors) {
1145                                 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1146                         } else {
1147                                 _channel_selector->set_default_channel_color();
1148                         }
1149                 }
1150
1151                 _color_mode = mode;
1152                 set_gui_property ("color-mode", enum_2_string(_color_mode));
1153                 if (redisplay) {
1154                         _view->redisplay_track();
1155                 }
1156         }
1157 }
1158
1159 void
1160 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1161 {
1162         if (apply_to_selection) {
1163                 _editor.get_selection().tracks.foreach_midi_time_axis (
1164                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1165         } else {
1166                 if (!_ignore_signals) {
1167                         midi_view()->set_note_range(range);
1168                 }
1169         }
1170 }
1171
1172 void
1173 MidiTimeAxisView::update_range()
1174 {
1175 }
1176
1177 void
1178 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1179 {
1180         using namespace MIDI::Name;
1181
1182         if (apply_to_selection) {
1183                 _editor.get_selection().tracks.foreach_midi_time_axis (
1184                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1185         } else {
1186                 if (midi_track()) {
1187                         // Show existing automation
1188                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1189
1190                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1191                                 create_automation_child(*i, true);
1192                         }
1193
1194                         // Show automation for all controllers named in midnam file
1195                         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1196                         if (gui_property (X_("midnam-model-name")) != "Generic" &&
1197                              device_names && !device_names->controls().empty()) {
1198                                 const std::string device_mode       = gui_property (X_("midnam-custom-device-mode"));
1199                                 const uint16_t    selected_channels = midi_track()->get_playback_channel_mask();
1200                                 for (uint32_t chn = 0; chn < 16; ++chn) {
1201                                         if ((selected_channels & (0x0001 << chn)) == 0) {
1202                                                 // Channel not in use
1203                                                 continue;
1204                                         }
1205
1206                                         boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1207                                                 device_mode, chn);
1208                                         if (!chan_names) {
1209                                                 continue;
1210                                         }
1211
1212                                         boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1213                                                 chan_names->control_list_name());
1214                                         if (!control_names) {
1215                                                 continue;
1216                                         }
1217
1218                                         for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1219                                              c != control_names->controls().end();
1220                                              ++c) {
1221                                                 const uint16_t ctl = c->second->number();
1222                                                 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1223                                                         /* Skip bank select controllers since they're handled specially */
1224                                                         const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1225                                                         create_automation_child(param, true);
1226                                                 }
1227                                         }
1228                                 }
1229                         }
1230                 }
1231
1232                 RouteTimeAxisView::show_all_automation ();
1233         }
1234 }
1235
1236 void
1237 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1238 {
1239         if (apply_to_selection) {
1240                 _editor.get_selection().tracks.foreach_midi_time_axis (
1241                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1242         } else {
1243                 if (midi_track()) {
1244                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1245
1246                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1247                                 create_automation_child (*i, true);
1248                         }
1249                 }
1250
1251                 RouteTimeAxisView::show_existing_automation ();
1252         }
1253 }
1254
1255 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1256  */
1257 void
1258 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1259 {
1260         if (param.type() == NullAutomation) {
1261                 return;
1262         }
1263
1264         AutomationTracks::iterator existing = _automation_tracks.find (param);
1265
1266         if (existing != _automation_tracks.end()) {
1267
1268                 /* automation track created because we had existing data for
1269                  * the processor, but visibility may need to be controlled
1270                  * since it will have been set visible by default.
1271                  */
1272
1273                 existing->second->set_marked_for_display (show);
1274
1275                 if (!no_redraw) {
1276                         request_redraw ();
1277                 }
1278
1279                 return;
1280         }
1281
1282         boost::shared_ptr<AutomationTimeAxisView> track;
1283         boost::shared_ptr<AutomationControl> control;
1284
1285
1286         switch (param.type()) {
1287
1288         case GainAutomation:
1289                 create_gain_automation_child (param, show);
1290                 break;
1291
1292         case MuteAutomation:
1293                 create_mute_automation_child (param, show);
1294                 break;
1295
1296         case PluginAutomation:
1297                 /* handled elsewhere */
1298                 break;
1299
1300         case MidiCCAutomation:
1301         case MidiPgmChangeAutomation:
1302         case MidiPitchBenderAutomation:
1303         case MidiChannelPressureAutomation:
1304         case MidiSystemExclusiveAutomation:
1305                 /* These controllers are region "automation" - they are owned
1306                  * by regions (and their MidiModels), not by the track. As a
1307                  * result there is no AutomationList/Line for the track, but we create
1308                  * a controller for the user to write immediate events, so the editor
1309                  * can act as a control surface for the present MIDI controllers.
1310                  *
1311                  * TODO: Record manipulation of the controller to regions?
1312                  */
1313
1314                 control = _route->automation_control(param, true);
1315                 track.reset (new AutomationTimeAxisView (
1316                                      _session,
1317                                      _route,
1318                                      control ? _route : boost::shared_ptr<Automatable> (),
1319                                      control,
1320                                      param,
1321                                      _editor,
1322                                      *this,
1323                                      true,
1324                                      parent_canvas,
1325                                      _route->describe_parameter(param)));
1326
1327                 if (_view) {
1328                         _view->foreach_regionview (
1329                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1330                 }
1331
1332                 add_automation_child (param, track, show);
1333                 if (selected ()) {
1334                         reshow_selection (_editor.get_selection().time);
1335                 }
1336
1337                 break;
1338
1339         case PanWidthAutomation:
1340         case PanElevationAutomation:
1341         case PanAzimuthAutomation:
1342                 ensure_pan_views (show);
1343                 break;
1344
1345         default:
1346                 error << "MidiTimeAxisView: unknown automation child "
1347                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1348         }
1349 }
1350
1351 void
1352 MidiTimeAxisView::route_active_changed ()
1353 {
1354         RouteUI::route_active_changed ();
1355         update_control_names();
1356 }
1357
1358 void
1359 MidiTimeAxisView::update_control_names ()
1360 {
1361         if (is_track()) {
1362                 if (_route->active()) {
1363                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1364                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1365                 } else {
1366                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1367                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1368                 }
1369         } else { // MIDI bus (which doesn't exist yet..)
1370                 if (_route->active()) {
1371                         controls_base_selected_name = "BusControlsBaseSelected";
1372                         controls_base_unselected_name = "BusControlsBaseUnselected";
1373                 } else {
1374                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1375                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1376                 }
1377         }
1378
1379         if (selected()) {
1380                 controls_ebox.set_name (controls_base_selected_name);
1381                 time_axis_frame.set_name (controls_base_selected_name);
1382         } else {
1383                 controls_ebox.set_name (controls_base_unselected_name);
1384                 time_axis_frame.set_name (controls_base_unselected_name);
1385         }
1386 }
1387
1388 void
1389 MidiTimeAxisView::set_note_selection (uint8_t note)
1390 {
1391         uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1392
1393         _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1394
1395         if (_view->num_selected_regionviews() == 0) {
1396                 _view->foreach_regionview (
1397                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1398                                     note, chn_mask));
1399         } else {
1400                 _view->foreach_selected_regionview (
1401                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1402                                     note, chn_mask));
1403         }
1404
1405         _editor.commit_reversible_selection_op();
1406 }
1407
1408 void
1409 MidiTimeAxisView::add_note_selection (uint8_t note)
1410 {
1411         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1412
1413         _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1414
1415         if (_view->num_selected_regionviews() == 0) {
1416                 _view->foreach_regionview (
1417                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1418                                     note, chn_mask));
1419         } else {
1420                 _view->foreach_selected_regionview (
1421                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1422                                     note, chn_mask));
1423         }
1424
1425         _editor.commit_reversible_selection_op();
1426 }
1427
1428 void
1429 MidiTimeAxisView::extend_note_selection (uint8_t note)
1430 {
1431         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1432
1433         _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1434
1435         if (_view->num_selected_regionviews() == 0) {
1436                 _view->foreach_regionview (
1437                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1438                                     note, chn_mask));
1439         } else {
1440                 _view->foreach_selected_regionview (
1441                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1442                                     note, chn_mask));
1443         }
1444
1445         _editor.commit_reversible_selection_op();
1446 }
1447
1448 void
1449 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1450 {
1451         const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1452
1453         _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1454
1455         if (_view->num_selected_regionviews() == 0) {
1456                 _view->foreach_regionview (
1457                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1458                                     note, chn_mask));
1459         } else {
1460                 _view->foreach_selected_regionview (
1461                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1462                                     note, chn_mask));
1463         }
1464
1465         _editor.commit_reversible_selection_op();
1466 }
1467
1468 void
1469 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1470 {
1471         _view->foreach_regionview (
1472                 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1473 }
1474
1475 void
1476 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1477 {
1478         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1479 }
1480
1481 void
1482 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1483 {
1484         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1485 }
1486
1487 void
1488 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1489 {
1490         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1491 }
1492
1493 void
1494 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1495 {
1496         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1497 }
1498
1499 void
1500 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1501 {
1502         Evoral::Sequence<Evoral::Beats>::Notes selected;
1503         dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1504
1505         std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1506
1507         Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1508         for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1509                 notes.insert (*sel_it);
1510         }
1511
1512         if (!notes.empty()) {
1513                 selection.push_back (make_pair ((rv)->region()->id(), notes));
1514         }
1515 }
1516
1517 void
1518 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1519 {
1520         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1521            the right ones.
1522         */
1523
1524         const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1525         bool changed = false;
1526
1527         no_redraw = true;
1528
1529         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1530
1531                 for (uint32_t chn = 0; chn < 16; ++chn) {
1532                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1533                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1534
1535                         if (!track) {
1536                                 continue;
1537                         }
1538
1539                         if ((selected_channels & (0x0001 << chn)) == 0) {
1540                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1541                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1542                                 */
1543                                 changed = track->set_marked_for_display (false) || changed;
1544                         } else {
1545                                 changed = track->set_marked_for_display (true) || changed;
1546                         }
1547                 }
1548         }
1549
1550         no_redraw = false;
1551
1552         /* TODO: Bender, Pressure */
1553
1554         /* invalidate the controller menu, so that we rebuild it next time */
1555         _controller_menu_map.clear ();
1556         delete controller_menu;
1557         controller_menu = 0;
1558
1559         if (changed) {
1560                 request_redraw ();
1561         }
1562 }
1563
1564 Gtk::CheckMenuItem*
1565 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1566 {
1567         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1568         if (m) {
1569                 return m;
1570         }
1571
1572         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1573         if (i != _controller_menu_map.end()) {
1574                 return i->second;
1575         }
1576
1577         i = _channel_command_menu_map.find (param);
1578         if (i != _channel_command_menu_map.end()) {
1579                 return i->second;
1580         }
1581
1582         return 0;
1583 }
1584
1585 boost::shared_ptr<MidiRegion>
1586 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1587 {
1588         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1589         MusicFrame pos (f, 0);
1590
1591         if (commit) {
1592                 real_editor->begin_reversible_command (Operations::create_region);
1593         }
1594         playlist()->clear_changes ();
1595
1596         real_editor->snap_to (pos, RoundNearest);
1597
1598         boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1599         PropertyList plist;
1600
1601         plist.add (ARDOUR::Properties::start, 0);
1602         plist.add (ARDOUR::Properties::length, length);
1603         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1604
1605         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1606         /* sets beat position */
1607         region->set_position (pos.frame, pos.division);
1608         playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1609         _session->add_command (new StatefulDiffCommand (playlist()));
1610
1611         if (commit) {
1612                 real_editor->commit_reversible_command ();
1613         }
1614
1615         return boost::dynamic_pointer_cast<MidiRegion>(region);
1616 }
1617
1618 void
1619 MidiTimeAxisView::ensure_step_editor ()
1620 {
1621         if (!_step_editor) {
1622                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1623         }
1624 }
1625
1626 void
1627 MidiTimeAxisView::start_step_editing ()
1628 {
1629         ensure_step_editor ();
1630         _step_editor->start_step_editing ();
1631
1632 }
1633 void
1634 MidiTimeAxisView::stop_step_editing ()
1635 {
1636         if (_step_editor) {
1637                 _step_editor->stop_step_editing ();
1638         }
1639 }
1640
1641 /** @return channel (counted from 0) to add an event to, based on the current setting
1642  *  of the channel selector.
1643  */
1644 uint8_t
1645 MidiTimeAxisView::get_channel_for_add () const
1646 {
1647         uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1648         int chn_cnt = 0;
1649         uint8_t channel = 0;
1650
1651         /* pick the highest selected channel, unless all channels are selected,
1652            which is interpreted to mean channel 1 (zero)
1653         */
1654
1655         for (uint16_t i = 0; i < 16; ++i) {
1656                 if (chn_mask & (1<<i)) {
1657                         channel = i;
1658                         chn_cnt++;
1659                 }
1660         }
1661
1662         if (chn_cnt == 16) {
1663                 channel = 0;
1664         }
1665
1666         return channel;
1667 }
1668
1669 void
1670 MidiTimeAxisView::note_range_changed ()
1671 {
1672         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1673         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1674 }
1675
1676 void
1677 MidiTimeAxisView::contents_height_changed ()
1678 {
1679         _range_scroomer->queue_resize ();
1680 }
1681
1682 bool
1683 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1684 {
1685         if (!_editor.internal_editing()) {
1686                 // Non-internal paste, paste regions like any other route
1687                 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1688         }
1689
1690         return midi_view()->paste(pos, selection, ctx, sub_num);
1691 }