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