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