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