Fix session range location by hooking into the undo system. Fixes #3654.
[ardour.git] / gtk2_ardour / midi_time_axis.cc
1 /*
2     Copyright (C) 2000 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cstdlib>
20 #include <cmath>
21
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25
26 #include <sigc++/bind.h>
27
28 #include "pbd/error.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/whitespace.h"
31 #include "pbd/basename.h"
32 #include "pbd/enumwriter.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/stateful_diff_command.h"
35
36 #include "gtkmm2ext/gtk_ui.h"
37 #include "gtkmm2ext/selector.h"
38 #include "gtkmm2ext/bindable_button.h"
39 #include "gtkmm2ext/utils.h"
40
41 #include "ardour/file_source.h"
42 #include "ardour/midi_playlist.h"
43 #include "ardour/midi_diskstream.h"
44 #include "ardour/midi_patch_manager.h"
45 #include "ardour/midi_source.h"
46 #include "ardour/processor.h"
47 #include "ardour/ladspa_plugin.h"
48 #include "ardour/location.h"
49 #include "ardour/playlist.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/session.h"
52 #include "ardour/session_playlist.h"
53 #include "ardour/tempo.h"
54 #include "ardour/utils.h"
55 #include "ardour/operations.h"
56
57 #include "midi++/names.h"
58
59 #include "add_midi_cc_track_dialog.h"
60 #include "ardour_ui.h"
61 #include "automation_line.h"
62 #include "automation_time_axis.h"
63 #include "canvas-note-event.h"
64 #include "canvas_impl.h"
65 #include "crossfade_view.h"
66 #include "editor.h"
67 #include "enums.h"
68 #include "ghostregion.h"
69 #include "gui_thread.h"
70 #include "keyboard.h"
71 #include "midi_scroomer.h"
72 #include "midi_streamview.h"
73 #include "midi_region_view.h"
74 #include "midi_time_axis.h"
75 #include "piano_roll_header.h"
76 #include "playlist_selector.h"
77 #include "plugin_selector.h"
78 #include "plugin_ui.h"
79 #include "point_selection.h"
80 #include "prompter.h"
81 #include "region_view.h"
82 #include "rgb_macros.h"
83 #include "selection.h"
84 #include "step_editor.h"
85 #include "simplerect.h"
86 #include "utils.h"
87
88 #include "ardour/midi_track.h"
89
90 #include "i18n.h"
91
92 using namespace ARDOUR;
93 using namespace PBD;
94 using namespace Gtk;
95 using namespace Gtkmm2ext;
96 using namespace Editing;
97
98 // Minimum height at which a control is displayed
99 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
100 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
101
102 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess,
103                 boost::shared_ptr<Route> rt, Canvas& canvas)
104         : AxisView(sess) // virtually inherited
105         , RouteTimeAxisView(ed, sess, rt, canvas)
106         , _ignore_signals(false)
107         , _range_scroomer(0)
108         , _piano_roll_header(0)
109         , _note_mode(Sustained)
110         , _note_mode_item(0)
111         , _percussion_mode_item(0)
112         , _color_mode(MeterColors)
113         , _meter_color_mode_item(0)
114         , _channel_color_mode_item(0)
115         , _track_color_mode_item(0)
116         , _step_edit_item (0)
117         , _midi_thru_item (0)
118         , default_channel_menu (0)
119         , controller_menu (0)
120         , _step_editor (0)
121 {
122         subplugin_menu.set_name ("ArdourContextMenu");
123
124         _view = new MidiStreamView (*this);
125
126         ignore_toggle = false;
127         
128         mute_button->set_active (false);
129         solo_button->set_active (false);
130
131         if (is_midi_track()) {
132                 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
133                 _note_mode = midi_track()->note_mode();
134         } else { // MIDI bus (which doesn't exist yet..)
135                 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
136         }
137
138         /* map current state of the route */
139
140         processors_changed (RouteProcessorChange ());
141
142         ensure_xml_node ();
143
144         set_state (*xml_node, Stateful::loading_state_version);
145
146         _route->processors_changed.connect (*this, invalidator (*this), ui_bind (&MidiTimeAxisView::processors_changed, this, _1), gui_context());
147
148         if (is_track()) {
149                 _piano_roll_header = new PianoRollHeader(*midi_view());
150
151                 _piano_roll_header->AddNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
152                 _piano_roll_header->ExtendNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
153                 _piano_roll_header->ToggleNoteSelection.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
154
155                 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
156
157                 controls_hbox.pack_start(*_range_scroomer);
158                 controls_hbox.pack_start(*_piano_roll_header);
159
160                 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
161                 controls_base_selected_name = "MidiTrackControlsBaseSelected";
162                 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
163
164                 midi_view()->NoteRangeChanged.connect (sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
165
166                 /* ask for notifications of any new RegionViews */
167                 _view->RegionViewAdded.connect (sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
168                 
169                 if (!_editor.have_idled()) {
170                         /* first idle will do what we need */
171                 } else {
172                         first_idle ();
173                 }
174         }
175
176         HBox* midi_controls_hbox = manage(new HBox());
177
178         MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
179
180         MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
181         for (; m != patch_manager.all_models().end(); ++m) {
182                 _model_selector.append_text(m->c_str());
183         }
184
185         _model_selector.signal_changed().connect(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
186
187         _custom_device_mode_selector.signal_changed().connect(
188                         sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
189
190         // TODO: persist the choice
191         // this initializes the comboboxes and sends out the signal
192         _model_selector.set_active(0);
193
194         midi_controls_hbox->pack_start(_channel_selector, true, false);
195         if (!patch_manager.all_models().empty()) {
196                 _midi_controls_box.pack_start(_model_selector, true, false);
197                 _midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
198         }
199
200         _midi_controls_box.pack_start(*midi_controls_hbox, true, true);
201
202         controls_vbox.pack_start(_midi_controls_box, false, false);
203
204         // restore channel selector settings
205         _channel_selector.set_channel_mode(midi_track()->get_channel_mode(), midi_track()->get_channel_mask());
206         _channel_selector.mode_changed.connect(
207                 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
208         _channel_selector.mode_changed.connect(
209                 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
210
211         XMLProperty *prop;
212         if ((prop = xml_node->property ("color-mode")) != 0) {
213                 _color_mode = ColorMode (string_2_enum(prop->value(), _color_mode));
214                 if (_color_mode == ChannelColors) {
215                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
216                 }
217         }
218
219         if ((prop = xml_node->property ("note-mode")) != 0) {
220                 _note_mode = NoteMode (string_2_enum(prop->value(), _note_mode));
221                 if (_percussion_mode_item) {
222                         _percussion_mode_item->set_active (_note_mode == Percussive);
223                 }
224         }
225 }
226
227 void
228 MidiTimeAxisView::first_idle ()
229 {
230         if (is_track ()) {
231                 _view->attach ();
232         }
233 }
234
235 MidiTimeAxisView::~MidiTimeAxisView ()
236 {
237         delete _piano_roll_header;
238         _piano_roll_header = 0;
239
240         delete _range_scroomer;
241         _range_scroomer = 0;
242
243         delete controller_menu;
244         delete _step_editor;
245 }
246
247 void
248 MidiTimeAxisView::check_step_edit ()
249 {
250         _step_editor->check_step_edit ();
251 }
252
253 void 
254 MidiTimeAxisView::model_changed()
255 {
256         std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
257                 .custom_device_mode_names_by_model(_model_selector.get_active_text());
258
259         _custom_device_mode_selector.clear_items();
260
261         for (std::list<std::string>::const_iterator i = device_modes.begin();
262                         i != device_modes.end(); ++i) {
263                 cerr << "found custom device mode " << *i << " thread_id: " << pthread_self() << endl;
264                 _custom_device_mode_selector.append_text(*i);
265         }
266
267         _custom_device_mode_selector.set_active(0);
268 }
269
270 void MidiTimeAxisView::custom_device_mode_changed()
271 {
272         _midi_patch_settings_changed.emit(_model_selector.get_active_text(),
273                         _custom_device_mode_selector.get_active_text());
274 }
275
276 MidiStreamView*
277 MidiTimeAxisView::midi_view()
278 {
279         return dynamic_cast<MidiStreamView*>(_view);
280 }
281
282 guint32
283 MidiTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
284 {
285         ensure_xml_node ();
286         xml_node->add_property ("shown-editor", "yes");
287
288         guint32 ret = TimeAxisView::show_at (y, nth, parent);
289         return ret;
290 }
291
292 void
293 MidiTimeAxisView::hide ()
294 {
295         ensure_xml_node ();
296         xml_node->add_property ("shown-editor", "no");
297
298         TimeAxisView::hide ();
299 }
300
301 void
302 MidiTimeAxisView::set_height (uint32_t h)
303 {
304         RouteTimeAxisView::set_height (h);
305
306         if (height >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
307                 _midi_controls_box.show_all ();
308         } else {
309                 _midi_controls_box.hide();
310         }
311
312         if (height >= KEYBOARD_MIN_HEIGHT) {
313                 if (is_track() && _range_scroomer)
314                         _range_scroomer->show();
315                 if (is_track() && _piano_roll_header)
316                         _piano_roll_header->show();
317         } else {
318                 if (is_track() && _range_scroomer)
319                         _range_scroomer->hide();
320                 if (is_track() && _piano_roll_header)
321                         _piano_roll_header->hide();
322         }
323 }
324
325 void
326 MidiTimeAxisView::append_extra_display_menu_items ()
327 {
328         using namespace Menu_Helpers;
329
330         MenuList& items = display_menu->items();
331
332         // Note range
333         Menu *range_menu = manage(new Menu);
334         MenuList& range_items = range_menu->items();
335         range_menu->set_name ("ArdourContextMenu");
336
337         range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
338                         sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
339                         MidiStreamView::FullRange)));
340
341         range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
342                         sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
343                         MidiStreamView::ContentsRange)));
344
345         items.push_back (MenuElem (_("Note range"), *range_menu));
346         items.push_back (MenuElem (_("Note mode"), *build_note_mode_menu()));
347         items.push_back (MenuElem (_("Default Channel"), *build_def_channel_menu()));
348
349         items.push_back (CheckMenuElem (_("MIDI Thru"), sigc::mem_fun(*this, &MidiTimeAxisView::toggle_midi_thru)));
350         _midi_thru_item = dynamic_cast<CheckMenuItem*>(&items.back());
351 }
352
353 Gtk::Menu*
354 MidiTimeAxisView::build_def_channel_menu ()
355 {
356         using namespace Menu_Helpers;
357
358         default_channel_menu = manage (new Menu ());
359
360         uint8_t defchn = midi_track()->default_channel();
361         MenuList& def_channel_items = default_channel_menu->items();
362         RadioMenuItem* item;
363         RadioMenuItem::Group dc_group;
364
365         for (int i = 0; i < 16; ++i) {
366                 char buf[4];
367                 snprintf (buf, sizeof (buf), "%d", i+1);
368
369                 def_channel_items.push_back (RadioMenuElem (dc_group, buf,
370                                                             sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_default_channel), i)));
371                 item = dynamic_cast<RadioMenuItem*>(&def_channel_items.back());
372                 item->set_active ((i == defchn));
373         }
374
375         return default_channel_menu;
376 }
377
378 void
379 MidiTimeAxisView::set_default_channel (int chn)
380 {
381         midi_track()->set_default_channel (chn);
382 }
383
384 void
385 MidiTimeAxisView::toggle_midi_thru ()
386 {
387         if (!_midi_thru_item) {
388                 return;
389         }
390
391         bool view_yn = _midi_thru_item->get_active();
392         if (view_yn != midi_track()->midi_thru()) {
393                 midi_track()->set_midi_thru (view_yn);
394         }
395 }
396
397 void
398 MidiTimeAxisView::build_automation_action_menu ()
399 {
400         using namespace Menu_Helpers;
401
402         /* If we have a controller menu, we need to detach it before
403            RouteTimeAxis::build_automation_action_menu destroys the
404            menu it is attached to.  Otherwise GTK destroys
405            controller_menu's gobj, meaning that it can't be reattached
406            below.  See bug #3134.
407         */
408            
409         if (controller_menu) {
410                 detach_menu (*controller_menu);
411         }
412
413         _channel_command_menu_map.clear ();
414         RouteTimeAxisView::build_automation_action_menu ();
415
416         MenuList& automation_items = automation_action_menu->items();
417         
418         uint16_t selected_channels = _channel_selector.get_selected_channels();
419
420         if (selected_channels !=  0) {
421
422                 automation_items.push_back (SeparatorElem());
423
424                 /* these 2 MIDI "command" types are semantically more like automation than note data,
425                    but they are not MIDI controllers. We give them special status in this menu, since
426                    they will not show up in the controller list and anyone who actually knows
427                    something about MIDI (!) would not expect to find them there.
428                 */
429
430                 add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
431                 add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
432                 
433                 /* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
434                    since it might need to be updated after a channel mode change or other change. Also detach it
435                    first in case it has been used anywhere else.
436                 */
437                 
438                 build_controller_menu ();
439                 
440                 automation_items.push_back (SeparatorElem());
441                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
442         } else {
443                 automation_items.push_back (MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
444         }
445                 
446 }
447
448 void
449 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
450 {
451         uint16_t selected_channels = _channel_selector.get_selected_channels();
452         
453         for (uint8_t chn = 0; chn < 16; chn++) {
454                 if (selected_channels & (0x0001 << chn)) {
455                         
456                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
457                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
458
459                         if (menu) {
460                                 menu->set_active (yn);
461                         }
462                 }
463         }
464 }
465
466 void
467 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items, const string& label, AutomationType auto_type, uint8_t cmd)
468 {
469         using namespace Menu_Helpers;
470
471         /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
472          */
473
474         uint16_t selected_channels = _channel_selector.get_selected_channels();
475         int chn_cnt = 0;
476         
477         for (uint8_t chn = 0; chn < 16; chn++) {
478                 if (selected_channels & (0x0001 << chn)) {
479                         if (++chn_cnt > 1) {
480                                 break;
481                         }
482                 }
483         }
484         
485         if (chn_cnt > 1) {
486                 
487                 /* multiple channels - create a submenu, with 1 item per channel */
488                 
489                 Menu* chn_menu = manage (new Menu);
490                 MenuList& chn_items (chn_menu->items());
491                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
492
493                 /* add a couple of items to hide/show all of them */
494
495                 chn_items.push_back (MenuElem (_("Hide all channels"),
496                                                     sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility), 
497                                                                 false, param_without_channel)));
498                 chn_items.push_back (MenuElem (_("Show all channels"),
499                                                     sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility), 
500                                                                 true, param_without_channel)));
501                 
502                 for (uint8_t chn = 0; chn < 16; chn++) {
503                         if (selected_channels & (0x0001 << chn)) {
504                                 
505                                 /* for each selected channel, add a menu item for this controller */
506                                 
507                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
508                                 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
509                                                                     sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
510                                                                                 fully_qualified_param)));
511                                 
512                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
513                                 bool visible = false;
514                                 
515                                 if (track) {
516                                         if (track->marked_for_display()) {
517                                                 visible = true;
518                                         }
519                                 }
520
521                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
522                                 _channel_command_menu_map[fully_qualified_param] = cmi;
523                                 cmi->set_active (visible);
524                         }
525                 }
526                 
527                 /* now create an item in the parent menu that has the per-channel list as a submenu */
528                         
529                 items.push_back (MenuElem (label, *chn_menu));
530                 
531         } else {
532                 
533                 /* just one channel - create a single menu item for this command+channel combination*/
534                 
535                 for (uint8_t chn = 0; chn < 16; chn++) {
536                         if (selected_channels & (0x0001 << chn)) {
537                                 
538                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
539                                 items.push_back (CheckMenuElem (label,
540                                                                 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
541                                                                             fully_qualified_param)));
542                                 
543                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
544                                 bool visible = false;
545                                 
546                                 if (track) {
547                                         if (track->marked_for_display()) {
548                                                 visible = true;
549                                         }
550                                 }
551                                 
552                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
553                                 _channel_command_menu_map[fully_qualified_param] = cmi;
554                                 cmi->set_active (visible);
555                                 
556                                 /* one channel only */
557                                 break;
558                         }
559                 }
560         }
561 }
562
563 void
564 MidiTimeAxisView::build_controller_menu ()
565 {
566         using namespace Menu_Helpers;
567
568         if (controller_menu) {
569                 /* it exists and has not been invalidated by a channel mode change, so just return it */
570                 return;
571         }
572
573         controller_menu = new Menu; // explicitly managed by us
574         MenuList& items (controller_menu->items());
575
576         /* create several "top level" menu items for sets of controllers (16 at a time), and populate each one with a submenu 
577            for each controller+channel combination covering the currently selected channels for this track
578         */
579
580         uint16_t selected_channels = _channel_selector.get_selected_channels();
581
582         /* count the number of selected channels because we will build a different menu structure if there is more than 1 selected.
583          */
584
585         int chn_cnt = 0;
586         
587         for (uint8_t chn = 0; chn < 16; chn++) {
588                 if (selected_channels & (0x0001 << chn)) {
589                         if (++chn_cnt > 1) {
590                                 break;
591                         }
592                 }
593         }
594         
595         /* loop over all 127 MIDI controllers, in groups of 16; except don't offer
596            bank select controllers, as they are handled by the `patch' code */
597
598         for (int i = 0; i < 127; i += 16) {
599
600                 Menu* ctl_menu = manage (new Menu);
601                 MenuList& ctl_items (ctl_menu->items());
602
603
604                 /* for each controller, consider whether to create a submenu or a single item */
605
606                 for (int ctl = i; ctl < i+16; ++ctl) {
607
608                         if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
609                                 continue;
610                         }
611
612                         if (chn_cnt > 1) {
613
614                                 /* multiple channels - create a submenu, with 1 item per channel */
615
616                                 Menu* chn_menu = manage (new Menu);
617                                 MenuList& chn_items (chn_menu->items());
618
619                                 /* add a couple of items to hide/show this controller on all channels */
620                                 
621                                 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
622                                 chn_items.push_back (MenuElem (_("Hide all channels"),
623                                                                     sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility), 
624                                                                                 false, param_without_channel)));
625                                 chn_items.push_back (MenuElem (_("Show all channels"),
626                                                                     sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility), 
627                                                                                 true, param_without_channel)));
628                 
629                                 for (uint8_t chn = 0; chn < 16; chn++) {
630                                         if (selected_channels & (0x0001 << chn)) {
631                                                 
632                                                 /* for each selected channel, add a menu item for this controller */
633                                                 
634                                                 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
635                                                 chn_items.push_back (CheckMenuElem (string_compose (_("Channel %1"), chn+1),
636                                                                                     sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
637                                                                                                 fully_qualified_param)));
638
639                                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
640                                                 bool visible = false;
641                                                 
642                                                 if (track) {
643                                                         if (track->marked_for_display()) {
644                                                                 visible = true;
645                                                         }
646                                                 }
647                                                 
648                                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
649                                                 _controller_menu_map[fully_qualified_param] = cmi;
650                                                 cmi->set_active (visible);
651                                         }
652                                 }
653                                 
654                                 /* add the per-channel menu to the list of controllers, with the name of the controller */
655                                 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, midi_name (ctl)), *chn_menu));
656                                 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
657                                       
658                         } else {
659
660                                 /* just one channel - create a single menu item for this ctl+channel combination*/
661
662                                 for (uint8_t chn = 0; chn < 16; chn++) {
663                                         if (selected_channels & (0x0001 << chn)) {
664                                                 
665                                                 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
666                                                 ctl_items.push_back (CheckMenuElem (_route->describe_parameter (fully_qualified_param),
667                                                                                     sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
668                                                                                                 fully_qualified_param)));
669                                                 
670                                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
671                                                 bool visible = false;
672                                                 
673                                                 if (track) {
674                                                         if (track->marked_for_display()) {
675                                                                 visible = true;
676                                                         }
677                                                 }
678                                                 
679                                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
680                                                 _controller_menu_map[fully_qualified_param] = cmi;
681                                                 cmi->set_active (visible);
682                                                 
683                                                 /* one channel only */
684                                                 break;
685                                         }
686                                 }
687                         }
688                 }
689                         
690                 /* add the menu for this block of controllers to the overall controller menu */
691
692                 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i+15), *ctl_menu));
693         }
694 }
695
696 Gtk::Menu*
697 MidiTimeAxisView::build_note_mode_menu()
698 {
699         using namespace Menu_Helpers;
700
701         Menu* mode_menu = manage (new Menu);
702         MenuList& items = mode_menu->items();
703         mode_menu->set_name ("ArdourContextMenu");
704
705         RadioMenuItem::Group mode_group;
706         items.push_back (RadioMenuElem (mode_group, _("Sustained"),
707                                 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
708         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
709         _note_mode_item->set_active(_note_mode == Sustained);
710
711         items.push_back (RadioMenuElem (mode_group, _("Percussive"),
712                                 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
713         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
714         _percussion_mode_item->set_active(_note_mode == Percussive);
715
716         return mode_menu;
717 }
718
719 Gtk::Menu*
720 MidiTimeAxisView::build_color_mode_menu()
721 {
722         using namespace Menu_Helpers;
723
724         Menu* mode_menu = manage (new Menu);
725         MenuList& items = mode_menu->items();
726         mode_menu->set_name ("ArdourContextMenu");
727
728         RadioMenuItem::Group mode_group;
729         items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
730                                 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), MeterColors)));
731         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
732         _meter_color_mode_item->set_active(_color_mode == MeterColors);
733
734         items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
735                                 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), ChannelColors)));
736         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
737         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
738
739         items.push_back (RadioMenuElem (mode_group, _("Track Color"),
740                                 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode), TrackColor)));
741         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
742         _channel_color_mode_item->set_active(_color_mode == TrackColor);
743
744         return mode_menu;
745 }
746
747 void
748 MidiTimeAxisView::set_note_mode(NoteMode mode)
749 {
750         if (_note_mode != mode || midi_track()->note_mode() != mode) {
751                 _note_mode = mode;
752                 midi_track()->set_note_mode(mode);
753                 xml_node->add_property ("note-mode", enum_2_string(_note_mode));
754                 _view->redisplay_track();
755         }
756 }
757
758 void
759 MidiTimeAxisView::set_color_mode(ColorMode mode)
760 {
761         if (_color_mode != mode) {
762                 if (mode == ChannelColors) {
763                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
764                 } else {
765                         _channel_selector.set_default_channel_color();
766                 }
767
768                 _color_mode = mode;
769                 xml_node->add_property ("color-mode", enum_2_string(_color_mode));
770                 _view->redisplay_track();
771         }
772 }
773
774 void
775 MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
776 {
777         if (!_ignore_signals)
778                 midi_view()->set_note_range(range);
779 }
780
781
782 void
783 MidiTimeAxisView::update_range()
784 {
785         MidiGhostRegion* mgr;
786
787         for(list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
788                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
789                         mgr->update_range();
790                 }
791         }
792 }
793
794 void
795 MidiTimeAxisView::show_all_automation ()
796 {
797         if (midi_track()) {
798                 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
799
800                 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
801                         create_automation_child(*i, true);
802                 }
803         }
804
805         RouteTimeAxisView::show_all_automation ();
806 }
807
808 void
809 MidiTimeAxisView::show_existing_automation ()
810 {
811         if (midi_track()) {
812                 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
813
814                 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
815                         create_automation_child(*i, true);
816                 }
817         }
818
819         RouteTimeAxisView::show_existing_automation ();
820 }
821
822 /** Create an automation track for the given parameter (pitch bend, channel pressure).
823  */
824 void
825 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
826 {
827         if (param.type() == NullAutomation) {
828                 cerr << "WARNING: Attempt to create NullAutomation child, ignoring" << endl;
829                 return;
830         }
831         
832         AutomationTracks::iterator existing = _automation_tracks.find (param);
833         if (existing != _automation_tracks.end()) {
834                 return;
835         }
836                 
837         if (param.type() == GainAutomation) {
838                 create_gain_automation_child (param, show);
839         } else {
840                 
841                 /* These controllers are region "automation", so we do not create
842                  * an AutomationList/Line for the track */
843                 
844                 boost::shared_ptr<AutomationControl> c = _route->get_control (param);
845                 assert (c);
846                 
847                 boost::shared_ptr<AutomationTimeAxisView> track(new AutomationTimeAxisView (_session,
848                                                                                             _route, boost::shared_ptr<ARDOUR::Automatable>(), c,
849                                                                                             _editor,
850                                                                                             *this,
851                                                                                             true,
852                                                                                             parent_canvas,
853                                                                                             _route->describe_parameter(param)));
854                 
855                 add_automation_child (param, track, show);
856         }
857 }
858
859
860 void
861 MidiTimeAxisView::route_active_changed ()
862 {
863         RouteUI::route_active_changed ();
864
865         if (is_track()) {
866                 if (_route->active()) {
867                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
868                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
869                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
870                 } else {
871                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
872                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
873                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
874                 }
875         } else {
876
877                 throw; // wha?
878
879                 if (_route->active()) {
880                         controls_ebox.set_name ("BusControlsBaseUnselected");
881                         controls_base_selected_name = "BusControlsBaseSelected";
882                         controls_base_unselected_name = "BusControlsBaseUnselected";
883                 } else {
884                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
885                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
886                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
887                 }
888         }
889 }
890
891
892
893 void
894 MidiTimeAxisView::add_note_selection (uint8_t note)
895 {
896         if (!_editor.internal_editing()) {
897                 return;
898         }
899
900         uint16_t chn_mask = _channel_selector.get_selected_channels();
901
902         if (_view->num_selected_regionviews() == 0) {
903                 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
904         } else {
905                 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view), note, chn_mask));
906         }
907 }
908
909 void
910 MidiTimeAxisView::extend_note_selection (uint8_t note)
911 {
912         if (!_editor.internal_editing()) {
913                 return;
914         }
915
916         uint16_t chn_mask = _channel_selector.get_selected_channels();
917
918         if (_view->num_selected_regionviews() == 0) {
919                 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
920         } else {
921                 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view), note, chn_mask));
922         }
923 }
924
925 void
926 MidiTimeAxisView::toggle_note_selection (uint8_t note)
927 {
928         if (!_editor.internal_editing()) {
929                 return;
930         }
931
932         uint16_t chn_mask = _channel_selector.get_selected_channels();
933
934         if (_view->num_selected_regionviews() == 0) {
935                 _view->foreach_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
936         } else {
937                 _view->foreach_selected_regionview (sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view), note, chn_mask));
938         }
939 }
940
941 void
942 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
943 {
944         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
945 }
946
947 void
948 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
949 {
950         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
951 }
952
953 void
954 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
955 {
956         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
957 }
958
959 void
960 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
961 {
962         /* hide all automation tracks that use the wrong channel(s) and show all those that use
963            the right ones.
964         */
965
966         uint16_t selected_channels = _channel_selector.get_selected_channels();
967         bool changed = false;
968
969         no_redraw = true;
970
971         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
972
973                 for (uint32_t chn = 0; chn < 16; ++chn) {
974                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
975                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
976
977                         if (!track) {
978                                 continue;
979                         }
980                         
981                         if ((selected_channels & (0x0001 << chn)) == 0) {
982                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden() 
983                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
984                                  */
985                                 changed = track->set_visibility (false) || changed;
986                         } else {
987                                 changed = track->set_visibility (true) || changed;
988                         }
989                 }
990         }
991
992         no_redraw = false;
993
994         /* TODO: Bender, Pressure */
995
996         /* invalidate the controller menu, so that we rebuilt it next time */
997         _controller_menu_map.clear ();
998         delete controller_menu;
999         controller_menu = 0;
1000
1001         if (changed) {
1002                 _route->gui_changed ("track_height", this);
1003         }
1004 }
1005
1006 Gtk::CheckMenuItem*
1007 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1008 {
1009         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1010         if (m) {
1011                 return m;
1012         }
1013
1014         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1015         if (i != _controller_menu_map.end()) {
1016                 return i->second;
1017         }
1018
1019         i = _channel_command_menu_map.find (param);
1020         if (i != _channel_command_menu_map.end()) {
1021                 return i->second;
1022         }
1023
1024         return 0;
1025 }
1026
1027 boost::shared_ptr<MidiRegion>
1028 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1029 {
1030         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1031
1032         real_editor->begin_reversible_command (Operations::create_region);
1033         playlist()->clear_changes ();
1034
1035         real_editor->snap_to (pos, 0);
1036         
1037         boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
1038                                                                                   view()->trackview().track()->name());
1039         PropertyList plist; 
1040         
1041         plist.add (ARDOUR::Properties::start, 0);
1042         plist.add (ARDOUR::Properties::length, length);
1043         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1044         
1045         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1046         
1047         playlist()->add_region (region, pos);
1048         _session->add_command (new StatefulDiffCommand (playlist()));
1049
1050         if (commit) {
1051                 real_editor->commit_reversible_command ();
1052         }
1053
1054         return boost::dynamic_pointer_cast<MidiRegion>(region);
1055 }
1056
1057 void 
1058 MidiTimeAxisView::start_step_editing ()
1059 {
1060         if (!_step_editor) {
1061                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1062         }
1063
1064         _step_editor->start_step_editing ();
1065
1066 }
1067 void 
1068 MidiTimeAxisView::stop_step_editing ()
1069 {
1070         if (_step_editor) {
1071                 _step_editor->stop_step_editing ();
1072         }
1073 }