Set MIDI device model to "Generic" by default (previously was unset).
[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/event_type_map.h"
42 #include "ardour/midi_patch_manager.h"
43 #include "ardour/midi_playlist.h"
44 #include "ardour/midi_region.h"
45 #include "ardour/midi_source.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/operations.h"
48 #include "ardour/playlist.h"
49 #include "ardour/region.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/route.h"
52 #include "ardour/session.h"
53 #include "ardour/session_object.h"
54 #include "ardour/source.h"
55 #include "ardour/track.h"
56 #include "ardour/types.h"
57
58 #include "midi++/names.h"
59
60 #include "ardour_ui.h"
61 #include "ardour_button.h"
62 #include "automation_line.h"
63 #include "automation_time_axis.h"
64 #include "canvas-note-event.h"
65 #include "canvas_impl.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, Canvas& canvas)
103         : AxisView(sess) // virtually inherited
104         , RouteTimeAxisView(ed, sess, 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         , controller_menu (0)
117         , _step_editor (0)
118 {
119 }
120
121 void
122 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
123 {
124         _route = rt;
125         
126         _view = new MidiStreamView (*this);
127
128         if (is_track ()) {
129                 _piano_roll_header = new PianoRollHeader(*midi_view());
130                 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
131                 _range_scroomer->DoubleClicked.connect (
132                         sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
133                                     MidiStreamView::ContentsRange, false));
134         }
135
136         /* This next call will result in our height being set up, so it must come after
137            the creation of the piano roll / range scroomer as their visibility is set up
138            when our height is.
139         */
140         RouteTimeAxisView::set_route (rt);
141
142         _view->apply_color (_color, StreamView::RegionColor);
143
144         subplugin_menu.set_name ("ArdourContextMenu");
145
146         if (!gui_property ("note-range-min").empty ()) {
147                 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
148                                                atoi (gui_property ("note-range-max").c_str()),
149                                                true);
150         }
151
152         midi_view()->NoteRangeChanged.connect (
153                 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
154         _view->ContentsHeightChanged.connect (
155                 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
156
157         ignore_toggle = false;
158
159         if (is_midi_track()) {
160                 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
161                 _note_mode = midi_track()->note_mode();
162         } else { // MIDI bus (which doesn't exist yet..)
163                 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
164         }
165
166         /* map current state of the route */
167
168         processors_changed (RouteProcessorChange ());
169
170         _route->processors_changed.connect (*this, invalidator (*this),
171                                             boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
172                                             gui_context());
173
174         if (is_track()) {
175                 _piano_roll_header->SetNoteSelection.connect (
176                         sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
177                 _piano_roll_header->AddNoteSelection.connect (
178                         sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
179                 _piano_roll_header->ExtendNoteSelection.connect (
180                         sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
181                 _piano_roll_header->ToggleNoteSelection.connect (
182                         sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
183
184                 /* Suspend updates of the StreamView during scroomer drags to speed things up */
185                 _range_scroomer->DragStarting.connect (
186                         sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
187                 _range_scroomer->DragFinishing.connect (
188                         sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
189
190                 /* Put the scroomer and the keyboard in a VBox with a padding
191                    label so that they can be reduced in height for stacked-view
192                    tracks.
193                 */
194                 VBox* v = manage (new VBox);
195                 HBox* h = manage (new HBox);
196                 h->pack_start (*_range_scroomer);
197                 h->pack_start (*_piano_roll_header);
198                 v->pack_start (*h, false, false);
199                 v->pack_start (*manage (new Label ("")), true, true);
200                 v->show ();
201                 h->show ();
202                 controls_hbox.pack_start(*v);
203
204                 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
205                 controls_base_selected_name = "MidiTrackControlsBaseSelected";
206                 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
207
208                 midi_view()->NoteRangeChanged.connect (
209                         sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
210
211                 /* ask for notifications of any new RegionViews */
212                 _view->RegionViewAdded.connect (
213                         sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
214
215                 if (!_editor.have_idled()) {
216                         /* first idle will do what we need */
217                 } else {
218                         first_idle ();
219                 }
220         }
221
222
223         MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
224
225         MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
226         for (; m != patch_manager.all_models().end(); ++m) {
227                 _midnam_model_selector.append_text(m->c_str());
228         }
229
230         if (gui_property (X_("midnam-model-name")).empty()) {
231                 set_gui_property (X_("midnam-model-name"), "Generic");
232         }
233
234         _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
235         _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
236
237         ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
238         ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
239
240         _midi_controls_box.set_homogeneous(false);
241         _midi_controls_box.set_border_width (10);
242
243         if (!patch_manager.all_models().empty()) {
244                 _channel_selector.set_border_width(2);
245                 _channel_selector.show_all ();
246
247                 _midi_controls_box.resize(3, 2);
248                 _midi_controls_box.attach(_channel_selector, 0, 2, 0, 1);
249                 
250                 _midi_controls_box.attach(*manage(new HSeparator()), 0, 2, 1, 2);
251
252                 _midnam_model_selector.set_size_request(22, 30);
253                 _midnam_model_selector.set_border_width(2);
254                 _midnam_model_selector.show ();
255                 _midi_controls_box.attach(_midnam_model_selector, 0, 1, 2, 3);
256
257                 _midnam_custom_device_mode_selector.set_size_request(10, 30);
258                 _midnam_custom_device_mode_selector.set_border_width(2);
259                 _midnam_custom_device_mode_selector.show ();
260
261                 _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 3, 4);
262         } else {
263                 _midi_controls_box.attach(_channel_selector, 0, 1, 0, 1);
264                 _channel_selector.show_all ();
265         }
266
267         model_changed();
268         custom_device_mode_changed();
269
270         _midnam_model_selector.signal_changed().connect(
271                 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
272         _midnam_custom_device_mode_selector.signal_changed().connect(
273                 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
274
275         controls_vbox.pack_start(_midi_controls_box, false, false);
276
277         // restore channel selector settings
278         _channel_selector.set_channel_mode(midi_track()->get_channel_mode(),
279                                            midi_track()->get_channel_mask());
280         _channel_selector.mode_changed.connect(
281                 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
282         _channel_selector.mode_changed.connect(
283                 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
284
285         const string color_mode = gui_property ("color-mode");
286         if (!color_mode.empty()) {
287                 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
288                 if (_color_mode == ChannelColors) {
289                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
290                 }
291         }
292
293         set_color_mode (_color_mode, true, false);
294
295         const string note_mode = gui_property ("note-mode");
296         if (!note_mode.empty()) {
297                 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
298                 if (_percussion_mode_item) {
299                         _percussion_mode_item->set_active (_note_mode == Percussive);
300                 }
301         }
302
303         /* Look for any GUI object state nodes that represent automation children
304          * that should exist, and create the children.
305          */
306
307         const list<string> gui_ids = gui_object_state().all_ids ();
308         for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
309                 PBD::ID route_id;
310                 bool has_parameter;
311                 Evoral::Parameter parameter (0, 0, 0);
312
313                 bool const p = AutomationTimeAxisView::parse_state_id (
314                         *i, route_id, has_parameter, parameter);
315                 if (p && route_id == _route->id () && has_parameter) {
316                         const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
317                         create_automation_child (parameter, string_is_affirmative (visible));
318                 }
319         }
320 }
321
322 void
323 MidiTimeAxisView::first_idle ()
324 {
325         if (is_track ()) {
326                 _view->attach ();
327         }
328 }
329
330 MidiTimeAxisView::~MidiTimeAxisView ()
331 {
332         delete _piano_roll_header;
333         _piano_roll_header = 0;
334
335         delete _range_scroomer;
336         _range_scroomer = 0;
337
338         delete controller_menu;
339         delete _step_editor;
340 }
341
342 void
343 MidiTimeAxisView::enter_internal_edit_mode ()
344 {
345         if (midi_view()) {
346                 midi_view()->enter_internal_edit_mode ();
347         }
348 }
349
350 void
351 MidiTimeAxisView::leave_internal_edit_mode ()
352 {
353         if (midi_view()) {
354                 midi_view()->leave_internal_edit_mode ();
355         }
356 }
357
358 void
359 MidiTimeAxisView::check_step_edit ()
360 {
361         ensure_step_editor ();
362         _step_editor->check_step_edit ();
363 }
364
365 void
366 MidiTimeAxisView::model_changed()
367 {
368         const Glib::ustring model = _midnam_model_selector.get_active_text();
369         set_gui_property (X_("midnam-model-name"), model);
370
371         const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
372                 .custom_device_mode_names_by_model(model);
373
374         _midnam_custom_device_mode_selector.clear_items();
375
376         if (device_modes.size() < 2) {
377                 _midnam_custom_device_mode_selector.hide();
378         } else {
379                 _midnam_custom_device_mode_selector.show();
380                 for (std::list<std::string>::const_iterator i = device_modes.begin();
381                      i != device_modes.end(); ++i) {
382                         _midnam_custom_device_mode_selector.append_text(*i);
383                 }
384         }
385
386         _midnam_custom_device_mode_selector.set_active(0);
387         
388         _route->instrument_info().set_external_instrument (
389                 _midnam_model_selector.get_active_text(),
390                 _midnam_custom_device_mode_selector.get_active_text());
391
392         // Rebuild controller menu
393         _controller_menu_map.clear ();
394         delete controller_menu;
395         controller_menu = 0;
396         build_automation_action_menu(false);
397 }
398
399 void
400 MidiTimeAxisView::custom_device_mode_changed()
401 {
402         const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
403         set_gui_property (X_("midnam-custom-device-mode"), mode);
404         _route->instrument_info().set_external_instrument (
405                 _midnam_model_selector.get_active_text(), mode);
406 }
407
408 MidiStreamView*
409 MidiTimeAxisView::midi_view()
410 {
411         return dynamic_cast<MidiStreamView*>(_view);
412 }
413
414 void
415 MidiTimeAxisView::set_height (uint32_t h)
416 {
417         if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
418                 _midi_controls_box.show ();
419         } else {
420                 _midi_controls_box.hide();
421         }
422         
423         if (h >= KEYBOARD_MIN_HEIGHT) {
424                 if (is_track() && _range_scroomer) {
425                         _range_scroomer->show();
426                 }
427                 if (is_track() && _piano_roll_header) {
428                         _piano_roll_header->show();
429                 }
430         } else {
431                 if (is_track() && _range_scroomer) {
432                         _range_scroomer->hide();
433                 }
434                 if (is_track() && _piano_roll_header) {
435                         _piano_roll_header->hide();
436                 }
437         }
438
439         /* We need to do this after changing visibility of our stuff, as it will
440            eventually trigger a call to Editor::reset_controls_layout_width(),
441            which needs to know if we have just shown or hidden a scroomer /
442            piano roll.
443         */
444         RouteTimeAxisView::set_height (h);
445 }
446
447 void
448 MidiTimeAxisView::append_extra_display_menu_items ()
449 {
450         using namespace Menu_Helpers;
451
452         MenuList& items = display_menu->items();
453
454         // Note range
455         Menu *range_menu = manage(new Menu);
456         MenuList& range_items = range_menu->items();
457         range_menu->set_name ("ArdourContextMenu");
458
459         range_items.push_back (
460                 MenuElem (_("Show Full Range"),
461                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range), 
462                                       MidiStreamView::FullRange, true)));
463
464         range_items.push_back (
465                 MenuElem (_("Fit Contents"),
466                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
467                                       MidiStreamView::ContentsRange, true)));
468
469         items.push_back (MenuElem (_("Note Range"), *range_menu));
470         items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
471
472         items.push_back (SeparatorElem ());
473 }
474
475 void
476 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
477 {
478         using namespace Menu_Helpers;
479
480         /* If we have a controller menu, we need to detach it before
481            RouteTimeAxis::build_automation_action_menu destroys the
482            menu it is attached to.  Otherwise GTK destroys
483            controller_menu's gobj, meaning that it can't be reattached
484            below.  See bug #3134.
485         */
486
487         if (controller_menu) {
488                 detach_menu (*controller_menu);
489         }
490
491         _channel_command_menu_map.clear ();
492         RouteTimeAxisView::build_automation_action_menu (for_selection);
493
494         MenuList& automation_items = automation_action_menu->items();
495
496         uint16_t selected_channels = _channel_selector.get_selected_channels();
497
498         if (selected_channels !=  0) {
499
500                 automation_items.push_back (SeparatorElem());
501
502                 /* these 2 MIDI "command" types are semantically more like automation
503                    than note data, but they are not MIDI controllers. We give them
504                    special status in this menu, since they will not show up in the
505                    controller list and anyone who actually knows something about MIDI
506                    (!) would not expect to find them there.
507                 */
508
509                 add_channel_command_menu_item (
510                         automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
511                 automation_items.back().set_sensitive (
512                         !for_selection || _editor.get_selection().tracks.size() == 1);
513                 add_channel_command_menu_item (
514                         automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
515                 automation_items.back().set_sensitive (
516                         !for_selection || _editor.get_selection().tracks.size() == 1);
517
518                 /* now all MIDI controllers. Always offer the possibility that we will
519                    rebuild the controllers menu since it might need to be updated after
520                    a channel mode change or other change. Also detach it first in case
521                    it has been used anywhere else.
522                 */
523
524                 build_controller_menu ();
525
526                 automation_items.push_back (SeparatorElem());
527                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
528                 automation_items.back().set_sensitive (
529                         !for_selection || _editor.get_selection().tracks.size() == 1);
530         } else {
531                 automation_items.push_back (
532                         MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
533                 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
534         }
535 }
536
537 void
538 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
539 {
540         const uint16_t selected_channels = _channel_selector.get_selected_channels();
541
542         for (uint8_t chn = 0; chn < 16; chn++) {
543                 if (selected_channels & (0x0001 << chn)) {
544
545                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
546                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
547
548                         if (menu) {
549                                 menu->set_active (yn);
550                         }
551                 }
552         }
553 }
554
555 void
556 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
557                                                  const string&           label,
558                                                  AutomationType          auto_type,
559                                                  uint8_t                 cmd)
560 {
561         using namespace Menu_Helpers;
562
563         /* count the number of selected channels because we will build a different menu
564            structure if there is more than 1 selected.
565          */
566
567         const uint16_t selected_channels = _channel_selector.get_selected_channels();
568         int chn_cnt = 0;
569
570         for (uint8_t chn = 0; chn < 16; chn++) {
571                 if (selected_channels & (0x0001 << chn)) {
572                         if (++chn_cnt > 1) {
573                                 break;
574                         }
575                 }
576         }
577
578         if (chn_cnt > 1) {
579
580                 /* multiple channels - create a submenu, with 1 item per channel */
581
582                 Menu* chn_menu = manage (new Menu);
583                 MenuList& chn_items (chn_menu->items());
584                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
585
586                 /* add a couple of items to hide/show all of them */
587
588                 chn_items.push_back (
589                         MenuElem (_("Hide all channels"),
590                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
591                                               false, param_without_channel)));
592                 chn_items.push_back (
593                         MenuElem (_("Show all channels"),
594                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
595                                               true, param_without_channel)));
596
597                 for (uint8_t chn = 0; chn < 16; chn++) {
598                         if (selected_channels & (0x0001 << chn)) {
599
600                                 /* for each selected channel, add a menu item for this controller */
601
602                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
603                                 chn_items.push_back (
604                                         CheckMenuElem (string_compose (_("Channel %1"), chn+1),
605                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
606                                                                    fully_qualified_param)));
607
608                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
609                                 bool visible = false;
610
611                                 if (track) {
612                                         if (track->marked_for_display()) {
613                                                 visible = true;
614                                         }
615                                 }
616
617                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
618                                 _channel_command_menu_map[fully_qualified_param] = cmi;
619                                 cmi->set_active (visible);
620                         }
621                 }
622
623                 /* now create an item in the parent menu that has the per-channel list as a submenu */
624
625                 items.push_back (MenuElem (label, *chn_menu));
626
627         } else {
628
629                 /* just one channel - create a single menu item for this command+channel combination*/
630
631                 for (uint8_t chn = 0; chn < 16; chn++) {
632                         if (selected_channels & (0x0001 << chn)) {
633
634                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
635                                 items.push_back (
636                                         CheckMenuElem (label,
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*>(&items.back());
650                                 _channel_command_menu_map[fully_qualified_param] = cmi;
651                                 cmi->set_active (visible);
652
653                                 /* one channel only */
654                                 break;
655                         }
656                 }
657         }
658 }
659
660 /** Add a single menu item for a controller on one channel. */
661 void
662 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
663                                                      int                     ctl,
664                                                      const std::string&      name)
665 {
666         using namespace Menu_Helpers;
667
668         const uint16_t selected_channels = _channel_selector.get_selected_channels();
669         for (uint8_t chn = 0; chn < 16; chn++) {
670                 if (selected_channels & (0x0001 << chn)) {
671
672                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
673                         ctl_items.push_back (
674                                 CheckMenuElem (
675                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn)),
676                                         sigc::bind (
677                                                 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
678                                                 fully_qualified_param)));
679                         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
680
681                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
682                                 fully_qualified_param);
683
684                         bool visible = false;
685                         if (track) {
686                                 if (track->marked_for_display()) {
687                                         visible = true;
688                                 }
689                         }
690
691                         CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
692                         _controller_menu_map[fully_qualified_param] = cmi;
693                         cmi->set_active (visible);
694
695                         /* one channel only */
696                         break;
697                 }
698         }
699 }
700
701 /** Add a submenu with 1 item per channel for a controller on many channels. */
702 void
703 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
704                                                     int                     ctl,
705                                                     const std::string&      name)
706 {
707         using namespace Menu_Helpers;
708
709         const uint16_t selected_channels = _channel_selector.get_selected_channels();
710
711         Menu* chn_menu = manage (new Menu);
712         MenuList& chn_items (chn_menu->items());
713
714         /* add a couple of items to hide/show this controller on all channels */
715
716         Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
717         chn_items.push_back (
718                 MenuElem (_("Hide all channels"),
719                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
720                                       false, param_without_channel)));
721         chn_items.push_back (
722                 MenuElem (_("Show all channels"),
723                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
724                                       true, param_without_channel)));
725
726         for (uint8_t chn = 0; chn < 16; chn++) {
727                 if (selected_channels & (0x0001 << chn)) {
728
729                         /* for each selected channel, add a menu item for this controller */
730
731                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
732                         chn_items.push_back (
733                                 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
734                                                sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
735                                                            fully_qualified_param)));
736
737                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
738                                 fully_qualified_param);
739                         bool visible = false;
740
741                         if (track) {
742                                 if (track->marked_for_display()) {
743                                         visible = true;
744                                 }
745                         }
746
747                         CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
748                         _controller_menu_map[fully_qualified_param] = cmi;
749                         cmi->set_active (visible);
750                 }
751         }
752
753         /* add the per-channel menu to the list of controllers, with the name of the controller */
754         ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
755                                        *chn_menu));
756         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
757 }
758
759 void
760 MidiTimeAxisView::build_controller_menu ()
761 {
762         using namespace Menu_Helpers;
763
764         if (controller_menu) {
765                 /* it exists and has not been invalidated by a channel mode change */
766                 return;
767         }
768
769         controller_menu = new Menu; // explicitly managed by us
770         MenuList& items (controller_menu->items());
771
772         /* create several "top level" menu items for sets of controllers (16 at a
773            time), and populate each one with a submenu for each controller+channel
774            combination covering the currently selected channels for this track
775         */
776
777         const uint16_t selected_channels = _channel_selector.get_selected_channels();
778
779         /* count the number of selected channels because we will build a different menu
780            structure if there is more than 1 selected.
781         */
782
783         int chn_cnt = 0;
784         for (uint8_t chn = 0; chn < 16; chn++) {
785                 if (selected_channels & (0x0001 << chn)) {
786                         if (++chn_cnt > 1) {
787                                 break;
788                         }
789                 }
790         }
791
792         using namespace MIDI::Name;
793         const Glib::ustring model = _midnam_model_selector.get_active_text();
794         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
795                 .document_by_model(model);
796         boost::shared_ptr<MasterDeviceNames> device_names;
797
798         if (midnam) {
799                 device_names = midnam->master_device_names(model);
800         }
801         
802         if (device_names && !device_names->controls().empty()) {
803                 /* Controllers names available in midnam file, generate fancy menu */
804                 unsigned n_items  = 0;
805                 unsigned n_groups = 0;
806                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
807                      l != device_names->controls().end(); ++l) {
808                         boost::shared_ptr<ControlNameList> name_list = *l;
809                         Menu*                              ctl_menu  = NULL;
810                         
811                         for (ControlNameList::Controls::const_iterator c = (*l)->controls().begin();
812                              c != (*l)->controls().end(); ++c) {
813                                 const int ctl = atoi((*c)->number().c_str());
814                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
815                                         /* Skip bank select controllers since they're handled specially */
816                                         continue;
817                                 }
818                                 
819                                 if (n_items == 0) {
820                                         /* Create a new submenu */
821                                         ctl_menu = manage (new Menu);
822                                 }
823                                 
824                                 MenuList& ctl_items (ctl_menu->items());
825                                 if (chn_cnt > 1) {
826                                         add_multi_channel_controller_item(ctl_items, ctl, (*c)->name());
827                                 } else {
828                                         add_single_channel_controller_item(ctl_items, ctl, (*c)->name());
829                                 }
830                                 
831                                 if (++n_items == 16 || c == (*l)->controls().end()) {
832                                         /* Submenu has 16 items, add it to controller menu and reset */
833                                         items.push_back(
834                                                 MenuElem(string_compose(_("Controllers %1-%2"),
835                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
836                                                          *ctl_menu));
837                                         ctl_menu = NULL;
838                                         n_items  = 0;
839                                         ++n_groups;
840                                 }
841                         }
842                 }
843         } else {
844                 /* No controllers names, generate generic numeric menu */
845                 for (int i = 0; i < 127; i += 16) {
846                         Menu*     ctl_menu = manage (new Menu);
847                         MenuList& ctl_items (ctl_menu->items());
848
849                         for (int ctl = i; ctl < i+16; ++ctl) {
850                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
851                                         /* Skip bank select controllers since they're handled specially */
852                                         continue;
853                                 }
854
855                                 if (chn_cnt > 1) {
856                                         add_multi_channel_controller_item(
857                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
858                                 } else {
859                                         add_single_channel_controller_item(
860                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
861                                 }
862                         }
863
864                         /* Add submenu for this block of controllers to controller menu */
865                         items.push_back (
866                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
867                                           *ctl_menu));
868                 }
869         }
870 }
871
872 Gtk::Menu*
873 MidiTimeAxisView::build_note_mode_menu()
874 {
875         using namespace Menu_Helpers;
876
877         Menu* mode_menu = manage (new Menu);
878         MenuList& items = mode_menu->items();
879         mode_menu->set_name ("ArdourContextMenu");
880
881         RadioMenuItem::Group mode_group;
882         items.push_back (
883                 RadioMenuElem (mode_group,_("Sustained"),
884                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
885                                            Sustained, true)));
886         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
887         _note_mode_item->set_active(_note_mode == Sustained);
888
889         items.push_back (
890                 RadioMenuElem (mode_group, _("Percussive"),
891                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
892                                            Percussive, true)));
893         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
894         _percussion_mode_item->set_active(_note_mode == Percussive);
895
896         return mode_menu;
897 }
898
899 Gtk::Menu*
900 MidiTimeAxisView::build_color_mode_menu()
901 {
902         using namespace Menu_Helpers;
903
904         Menu* mode_menu = manage (new Menu);
905         MenuList& items = mode_menu->items();
906         mode_menu->set_name ("ArdourContextMenu");
907
908         RadioMenuItem::Group mode_group;
909         items.push_back (
910                 RadioMenuElem (mode_group, _("Meter Colors"),
911                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
912                                            MeterColors, false, true, true)));
913         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
914         _meter_color_mode_item->set_active(_color_mode == MeterColors);
915
916         items.push_back (
917                 RadioMenuElem (mode_group, _("Channel Colors"),
918                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
919                                            ChannelColors, false, true, true)));
920         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
921         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
922
923         items.push_back (
924                 RadioMenuElem (mode_group, _("Track Color"),
925                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
926                                            TrackColor, false, true, true)));
927         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
928         _channel_color_mode_item->set_active(_color_mode == TrackColor);
929
930         return mode_menu;
931 }
932
933 void
934 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
935 {
936         if (apply_to_selection) {
937                 _editor.get_selection().tracks.foreach_midi_time_axis (
938                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
939         } else {
940                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
941                         _note_mode = mode;
942                         midi_track()->set_note_mode(mode);
943                         set_gui_property ("note-mode", enum_2_string(_note_mode));
944                         _view->redisplay_track();
945                 }
946         }
947 }
948
949 void
950 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
951 {
952         if (apply_to_selection) {
953                 _editor.get_selection().tracks.foreach_midi_time_axis (
954                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
955         } else {
956                 if (_color_mode == mode && !force) {
957                         return;
958                 }
959                 
960                 if (mode == ChannelColors) {
961                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
962                 } else {
963                         _channel_selector.set_default_channel_color();
964                 }
965                 
966                 _color_mode = mode;
967                 set_gui_property ("color-mode", enum_2_string(_color_mode));
968                 if (redisplay) {
969                         _view->redisplay_track();
970                 }
971         }
972 }
973
974 void
975 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
976 {
977         if (apply_to_selection) {
978                 _editor.get_selection().tracks.foreach_midi_time_axis (
979                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
980         } else {
981                 if (!_ignore_signals) {
982                         midi_view()->set_note_range(range);
983                 }
984         }
985 }
986
987 void
988 MidiTimeAxisView::update_range()
989 {
990         MidiGhostRegion* mgr;
991
992         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
993                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
994                         mgr->update_range();
995                 }
996         }
997 }
998
999 void
1000 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1001 {
1002         if (apply_to_selection) {
1003                 _editor.get_selection().tracks.foreach_midi_time_axis (
1004                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1005         } else {
1006                 if (midi_track()) {
1007                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1008
1009                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1010                                 create_automation_child(*i, true);
1011                         }
1012                 }
1013
1014                 RouteTimeAxisView::show_all_automation ();
1015         }
1016 }
1017
1018 void
1019 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1020 {
1021         if (apply_to_selection) {
1022                 _editor.get_selection().tracks.foreach_midi_time_axis (
1023                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1024         } else {
1025                 if (midi_track()) {
1026                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1027
1028                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1029                                 create_automation_child (*i, true);
1030                         }
1031                 }
1032
1033                 RouteTimeAxisView::show_existing_automation ();
1034         }
1035 }
1036
1037 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1038  */
1039 void
1040 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1041 {
1042         if (param.type() == NullAutomation) {
1043                 return;
1044         }
1045
1046         AutomationTracks::iterator existing = _automation_tracks.find (param);
1047
1048         if (existing != _automation_tracks.end()) {
1049
1050                 /* automation track created because we had existing data for
1051                  * the processor, but visibility may need to be controlled
1052                  * since it will have been set visible by default.
1053                  */
1054
1055                 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1056                         request_redraw ();
1057                 }
1058
1059                 return;
1060         }
1061
1062         boost::shared_ptr<AutomationTimeAxisView> track;
1063
1064         switch (param.type()) {
1065
1066         case GainAutomation:
1067                 create_gain_automation_child (param, show);
1068                 break;
1069
1070         case PluginAutomation:
1071                 /* handled elsewhere */
1072                 break;
1073
1074         case MidiCCAutomation:
1075         case MidiPgmChangeAutomation:
1076         case MidiPitchBenderAutomation:
1077         case MidiChannelPressureAutomation:
1078         case MidiSystemExclusiveAutomation:
1079                 /* These controllers are region "automation" - they are owned
1080                  * by regions (and their MidiModels), not by the track. As a
1081                  * result we do not create an AutomationList/Line for the track
1082                  * ... except here we are doing something!! XXX 
1083                  */
1084
1085                 track.reset (new AutomationTimeAxisView (
1086                                      _session,
1087                                      _route,
1088                                      boost::shared_ptr<Automatable> (),
1089                                      boost::shared_ptr<AutomationControl> (),
1090                                      param,
1091                                      _editor,
1092                                      *this,
1093                                      true,
1094                                      parent_canvas,
1095                                      _route->describe_parameter(param)));
1096
1097                 if (_view) {
1098                         _view->foreach_regionview (
1099                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1100                 }
1101
1102                 add_automation_child (param, track, show);
1103                 break;
1104
1105         default:
1106                 error << "MidiTimeAxisView: unknown automation child "
1107                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1108         }
1109 }
1110
1111 void
1112 MidiTimeAxisView::route_active_changed ()
1113 {
1114         RouteUI::route_active_changed ();
1115
1116         if (is_track()) {
1117                 if (_route->active()) {
1118                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1119                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1120                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1121                 } else {
1122                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1123                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1124                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1125                 }
1126         } else {
1127                 if (_route->active()) {
1128                         controls_ebox.set_name ("BusControlsBaseUnselected");
1129                         controls_base_selected_name = "BusControlsBaseSelected";
1130                         controls_base_unselected_name = "BusControlsBaseUnselected";
1131                 } else {
1132                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1133                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1134                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1135                 }
1136         }
1137 }
1138
1139 void
1140 MidiTimeAxisView::set_note_selection (uint8_t note)
1141 {
1142         if (!_editor.internal_editing()) {
1143                 return;
1144         }
1145
1146         uint16_t chn_mask = _channel_selector.get_selected_channels();
1147
1148         if (_view->num_selected_regionviews() == 0) {
1149                 _view->foreach_regionview (
1150                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1151                                     note, chn_mask));
1152         } else {
1153                 _view->foreach_selected_regionview (
1154                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1155                                     note, chn_mask));
1156         }
1157 }
1158
1159 void
1160 MidiTimeAxisView::add_note_selection (uint8_t note)
1161 {
1162         if (!_editor.internal_editing()) {
1163                 return;
1164         }
1165
1166         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1167
1168         if (_view->num_selected_regionviews() == 0) {
1169                 _view->foreach_regionview (
1170                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1171                                     note, chn_mask));
1172         } else {
1173                 _view->foreach_selected_regionview (
1174                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1175                                     note, chn_mask));
1176         }
1177 }
1178
1179 void
1180 MidiTimeAxisView::extend_note_selection (uint8_t note)
1181 {
1182         if (!_editor.internal_editing()) {
1183                 return;
1184         }
1185
1186         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1187
1188         if (_view->num_selected_regionviews() == 0) {
1189                 _view->foreach_regionview (
1190                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1191                                     note, chn_mask));
1192         } else {
1193                 _view->foreach_selected_regionview (
1194                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1195                                     note, chn_mask));
1196         }
1197 }
1198
1199 void
1200 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1201 {
1202         if (!_editor.internal_editing()) {
1203                 return;
1204         }
1205
1206         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1207
1208         if (_view->num_selected_regionviews() == 0) {
1209                 _view->foreach_regionview (
1210                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1211                                     note, chn_mask));
1212         } else {
1213                 _view->foreach_selected_regionview (
1214                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1215                                     note, chn_mask));
1216         }
1217 }
1218
1219 void
1220 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1221 {
1222         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1223 }
1224
1225 void
1226 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1227 {
1228         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1229 }
1230
1231 void
1232 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1233 {
1234         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1235 }
1236
1237 void
1238 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1239 {
1240         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1241 }
1242
1243 void
1244 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1245 {
1246         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1247            the right ones.
1248         */
1249
1250         const uint16_t selected_channels = _channel_selector.get_selected_channels();
1251         bool changed = false;
1252
1253         no_redraw = true;
1254
1255         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1256
1257                 for (uint32_t chn = 0; chn < 16; ++chn) {
1258                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1259                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1260
1261                         if (!track) {
1262                                 continue;
1263                         }
1264
1265                         if ((selected_channels & (0x0001 << chn)) == 0) {
1266                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1267                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1268                                 */
1269                                 changed = track->set_marked_for_display (false) || changed;
1270                         } else {
1271                                 changed = track->set_marked_for_display (true) || changed;
1272                         }
1273                 }
1274         }
1275
1276         no_redraw = false;
1277
1278         /* TODO: Bender, Pressure */
1279
1280         /* invalidate the controller menu, so that we rebuild it next time */
1281         _controller_menu_map.clear ();
1282         delete controller_menu;
1283         controller_menu = 0;
1284
1285         if (changed) {
1286                 request_redraw ();
1287         }
1288 }
1289
1290 Gtk::CheckMenuItem*
1291 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1292 {
1293         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1294         if (m) {
1295                 return m;
1296         }
1297
1298         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1299         if (i != _controller_menu_map.end()) {
1300                 return i->second;
1301         }
1302
1303         i = _channel_command_menu_map.find (param);
1304         if (i != _channel_command_menu_map.end()) {
1305                 return i->second;
1306         }
1307
1308         return 0;
1309 }
1310
1311 boost::shared_ptr<MidiRegion>
1312 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1313 {
1314         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1315
1316         real_editor->begin_reversible_command (Operations::create_region);
1317         playlist()->clear_changes ();
1318
1319         real_editor->snap_to (pos, 0);
1320
1321         boost::shared_ptr<Source> src = _session->create_midi_source_for_session (
1322                 view()->trackview().track().get(), view()->trackview().track()->name());
1323         PropertyList plist;
1324
1325         plist.add (ARDOUR::Properties::start, 0);
1326         plist.add (ARDOUR::Properties::length, length);
1327         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1328
1329         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1330
1331         playlist()->add_region (region, pos);
1332         _session->add_command (new StatefulDiffCommand (playlist()));
1333
1334         if (commit) {
1335                 real_editor->commit_reversible_command ();
1336         }
1337
1338         return boost::dynamic_pointer_cast<MidiRegion>(region);
1339 }
1340
1341 void
1342 MidiTimeAxisView::ensure_step_editor ()
1343 {
1344         if (!_step_editor) {
1345                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1346         }
1347 }
1348
1349 void
1350 MidiTimeAxisView::start_step_editing ()
1351 {
1352         ensure_step_editor ();
1353         _step_editor->start_step_editing ();
1354
1355 }
1356 void
1357 MidiTimeAxisView::stop_step_editing ()
1358 {
1359         if (_step_editor) {
1360                 _step_editor->stop_step_editing ();
1361         }
1362 }
1363
1364
1365 /** @return channel (counted from 0) to add an event to, based on the current setting
1366  *  of the channel selector.
1367  */
1368 uint8_t
1369 MidiTimeAxisView::get_channel_for_add () const
1370 {
1371         uint16_t const chn_mask = _channel_selector.get_selected_channels ();
1372         int chn_cnt = 0;
1373         uint8_t channel = 0;
1374
1375         /* pick the highest selected channel, unless all channels are selected,
1376            which is interpreted to mean channel 1 (zero)
1377         */
1378
1379         for (uint16_t i = 0; i < 16; ++i) {
1380                 if (chn_mask & (1<<i)) {
1381                         channel = i;
1382                         chn_cnt++;
1383                 }
1384         }
1385
1386         if (chn_cnt == 16) {
1387                 channel = 0;
1388         }
1389
1390         return channel;
1391 }
1392
1393 void
1394 MidiTimeAxisView::note_range_changed ()
1395 {
1396         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1397         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1398 }
1399
1400 void
1401 MidiTimeAxisView::contents_height_changed ()
1402 {
1403         _range_scroomer->set_size_request (-1, _view->child_height ());
1404 }