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