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