fix midnam-related crash introduced around 13892
[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;
786
787         if (midnam) {
788                 device_names = midnam->master_device_names(model);
789         }
790         
791         if (device_names && !device_names->controls().empty()) {
792                 /* Controllers names available in midnam file, generate fancy menu */
793                 unsigned n_items  = 0;
794                 unsigned n_groups = 0;
795                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
796                      l != device_names->controls().end(); ++l) {
797                         boost::shared_ptr<ControlNameList> name_list = *l;
798                         Menu*                              ctl_menu  = NULL;
799                         
800                         for (ControlNameList::Controls::const_iterator c = (*l)->controls().begin();
801                              c != (*l)->controls().end(); ++c) {
802                                 const int ctl = atoi((*c)->number().c_str());
803                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
804                                         /* Skip bank select controllers since they're handled specially */
805                                         continue;
806                                 }
807                                 
808                                 if (n_items == 0) {
809                                         /* Create a new submenu */
810                                         ctl_menu = manage (new Menu);
811                                 }
812                                 
813                                 MenuList& ctl_items (ctl_menu->items());
814                                 if (chn_cnt > 1) {
815                                         add_multi_channel_controller_item(ctl_items, ctl, (*c)->name());
816                                 } else {
817                                         add_single_channel_controller_item(ctl_items, ctl, (*c)->name());
818                                 }
819                                 
820                                 if (++n_items == 16 || c == (*l)->controls().end()) {
821                                         /* Submenu has 16 items, add it to controller menu and reset */
822                                         items.push_back(
823                                                 MenuElem(string_compose(_("Controllers %1-%2"),
824                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
825                                                          *ctl_menu));
826                                         ctl_menu = NULL;
827                                         n_items  = 0;
828                                         ++n_groups;
829                                 }
830                         }
831                 }
832         } else {
833                 /* No controllers names, generate generic numeric menu */
834                 for (int i = 0; i < 127; i += 16) {
835                         Menu*     ctl_menu = manage (new Menu);
836                         MenuList& ctl_items (ctl_menu->items());
837
838                         for (int ctl = i; ctl < i+16; ++ctl) {
839                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
840                                         /* Skip bank select controllers since they're handled specially */
841                                         continue;
842                                 }
843
844                                 if (chn_cnt > 1) {
845                                         add_multi_channel_controller_item(
846                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
847                                 } else {
848                                         add_single_channel_controller_item(
849                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
850                                 }
851                         }
852
853                         /* Add submenu for this block of controllers to controller menu */
854                         items.push_back (
855                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
856                                           *ctl_menu));
857                 }
858         }
859 }
860
861 Gtk::Menu*
862 MidiTimeAxisView::build_note_mode_menu()
863 {
864         using namespace Menu_Helpers;
865
866         Menu* mode_menu = manage (new Menu);
867         MenuList& items = mode_menu->items();
868         mode_menu->set_name ("ArdourContextMenu");
869
870         RadioMenuItem::Group mode_group;
871         items.push_back (
872                 RadioMenuElem (mode_group,_("Sustained"),
873                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
874                                            Sustained, true)));
875         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
876         _note_mode_item->set_active(_note_mode == Sustained);
877
878         items.push_back (
879                 RadioMenuElem (mode_group, _("Percussive"),
880                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
881                                            Percussive, true)));
882         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
883         _percussion_mode_item->set_active(_note_mode == Percussive);
884
885         return mode_menu;
886 }
887
888 Gtk::Menu*
889 MidiTimeAxisView::build_color_mode_menu()
890 {
891         using namespace Menu_Helpers;
892
893         Menu* mode_menu = manage (new Menu);
894         MenuList& items = mode_menu->items();
895         mode_menu->set_name ("ArdourContextMenu");
896
897         RadioMenuItem::Group mode_group;
898         items.push_back (
899                 RadioMenuElem (mode_group, _("Meter Colors"),
900                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
901                                            MeterColors, false, true, true)));
902         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
903         _meter_color_mode_item->set_active(_color_mode == MeterColors);
904
905         items.push_back (
906                 RadioMenuElem (mode_group, _("Channel Colors"),
907                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
908                                            ChannelColors, false, true, true)));
909         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
910         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
911
912         items.push_back (
913                 RadioMenuElem (mode_group, _("Track Color"),
914                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
915                                            TrackColor, false, true, true)));
916         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
917         _channel_color_mode_item->set_active(_color_mode == TrackColor);
918
919         return mode_menu;
920 }
921
922 void
923 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
924 {
925         if (apply_to_selection) {
926                 _editor.get_selection().tracks.foreach_midi_time_axis (
927                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
928         } else {
929                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
930                         _note_mode = mode;
931                         midi_track()->set_note_mode(mode);
932                         set_gui_property ("note-mode", enum_2_string(_note_mode));
933                         _view->redisplay_track();
934                 }
935         }
936 }
937
938 void
939 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
940 {
941         if (apply_to_selection) {
942                 _editor.get_selection().tracks.foreach_midi_time_axis (
943                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
944         } else {
945                 if (_color_mode == mode && !force) {
946                         return;
947                 }
948                 
949                 if (mode == ChannelColors) {
950                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
951                 } else {
952                         _channel_selector.set_default_channel_color();
953                 }
954                 
955                 _color_mode = mode;
956                 set_gui_property ("color-mode", enum_2_string(_color_mode));
957                 if (redisplay) {
958                         _view->redisplay_track();
959                 }
960         }
961 }
962
963 void
964 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
965 {
966         if (apply_to_selection) {
967                 _editor.get_selection().tracks.foreach_midi_time_axis (
968                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
969         } else {
970                 if (!_ignore_signals) {
971                         midi_view()->set_note_range(range);
972                 }
973         }
974 }
975
976 void
977 MidiTimeAxisView::update_range()
978 {
979         MidiGhostRegion* mgr;
980
981         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
982                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
983                         mgr->update_range();
984                 }
985         }
986 }
987
988 void
989 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
990 {
991         if (apply_to_selection) {
992                 _editor.get_selection().tracks.foreach_midi_time_axis (
993                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
994         } else {
995                 if (midi_track()) {
996                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
997
998                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
999                                 create_automation_child(*i, true);
1000                         }
1001                 }
1002
1003                 RouteTimeAxisView::show_all_automation ();
1004         }
1005 }
1006
1007 void
1008 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1009 {
1010         if (apply_to_selection) {
1011                 _editor.get_selection().tracks.foreach_midi_time_axis (
1012                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1013         } else {
1014                 if (midi_track()) {
1015                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1016
1017                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1018                                 create_automation_child (*i, true);
1019                         }
1020                 }
1021
1022                 RouteTimeAxisView::show_existing_automation ();
1023         }
1024 }
1025
1026 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1027  */
1028 void
1029 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1030 {
1031         if (param.type() == NullAutomation) {
1032                 return;
1033         }
1034
1035         AutomationTracks::iterator existing = _automation_tracks.find (param);
1036
1037         if (existing != _automation_tracks.end()) {
1038
1039                 /* automation track created because we had existing data for
1040                  * the processor, but visibility may need to be controlled
1041                  * since it will have been set visible by default.
1042                  */
1043
1044                 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1045                         request_redraw ();
1046                 }
1047
1048                 return;
1049         }
1050
1051         boost::shared_ptr<AutomationTimeAxisView> track;
1052
1053         switch (param.type()) {
1054
1055         case GainAutomation:
1056                 create_gain_automation_child (param, show);
1057                 break;
1058
1059         case PluginAutomation:
1060                 /* handled elsewhere */
1061                 break;
1062
1063         case MidiCCAutomation:
1064         case MidiPgmChangeAutomation:
1065         case MidiPitchBenderAutomation:
1066         case MidiChannelPressureAutomation:
1067         case MidiSystemExclusiveAutomation:
1068                 /* These controllers are region "automation" - they are owned
1069                  * by regions (and their MidiModels), not by the track. As a
1070                  * result we do not create an AutomationList/Line for the track
1071                  * ... except here we are doing something!! XXX 
1072                  */
1073
1074                 track.reset (new AutomationTimeAxisView (
1075                                      _session,
1076                                      _route,
1077                                      boost::shared_ptr<Automatable> (),
1078                                      boost::shared_ptr<AutomationControl> (),
1079                                      param,
1080                                      _editor,
1081                                      *this,
1082                                      true,
1083                                      parent_canvas,
1084                                      _route->describe_parameter(param)));
1085
1086                 if (_view) {
1087                         _view->foreach_regionview (
1088                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1089                 }
1090
1091                 add_automation_child (param, track, show);
1092                 break;
1093
1094         default:
1095                 error << "MidiTimeAxisView: unknown automation child "
1096                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1097         }
1098 }
1099
1100 void
1101 MidiTimeAxisView::route_active_changed ()
1102 {
1103         RouteUI::route_active_changed ();
1104
1105         if (is_track()) {
1106                 if (_route->active()) {
1107                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1108                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1109                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1110                 } else {
1111                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1112                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1113                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1114                 }
1115         } else {
1116                 if (_route->active()) {
1117                         controls_ebox.set_name ("BusControlsBaseUnselected");
1118                         controls_base_selected_name = "BusControlsBaseSelected";
1119                         controls_base_unselected_name = "BusControlsBaseUnselected";
1120                 } else {
1121                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1122                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1123                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1124                 }
1125         }
1126 }
1127
1128 void
1129 MidiTimeAxisView::set_note_selection (uint8_t note)
1130 {
1131         if (!_editor.internal_editing()) {
1132                 return;
1133         }
1134
1135         uint16_t chn_mask = _channel_selector.get_selected_channels();
1136
1137         if (_view->num_selected_regionviews() == 0) {
1138                 _view->foreach_regionview (
1139                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1140                                     note, chn_mask));
1141         } else {
1142                 _view->foreach_selected_regionview (
1143                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1144                                     note, chn_mask));
1145         }
1146 }
1147
1148 void
1149 MidiTimeAxisView::add_note_selection (uint8_t note)
1150 {
1151         if (!_editor.internal_editing()) {
1152                 return;
1153         }
1154
1155         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1156
1157         if (_view->num_selected_regionviews() == 0) {
1158                 _view->foreach_regionview (
1159                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1160                                     note, chn_mask));
1161         } else {
1162                 _view->foreach_selected_regionview (
1163                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1164                                     note, chn_mask));
1165         }
1166 }
1167
1168 void
1169 MidiTimeAxisView::extend_note_selection (uint8_t note)
1170 {
1171         if (!_editor.internal_editing()) {
1172                 return;
1173         }
1174
1175         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1176
1177         if (_view->num_selected_regionviews() == 0) {
1178                 _view->foreach_regionview (
1179                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1180                                     note, chn_mask));
1181         } else {
1182                 _view->foreach_selected_regionview (
1183                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1184                                     note, chn_mask));
1185         }
1186 }
1187
1188 void
1189 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1190 {
1191         if (!_editor.internal_editing()) {
1192                 return;
1193         }
1194
1195         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1196
1197         if (_view->num_selected_regionviews() == 0) {
1198                 _view->foreach_regionview (
1199                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1200                                     note, chn_mask));
1201         } else {
1202                 _view->foreach_selected_regionview (
1203                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1204                                     note, chn_mask));
1205         }
1206 }
1207
1208 void
1209 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1210 {
1211         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1212 }
1213
1214 void
1215 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1216 {
1217         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1218 }
1219
1220 void
1221 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1222 {
1223         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1224 }
1225
1226 void
1227 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1228 {
1229         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1230 }
1231
1232 void
1233 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1234 {
1235         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1236            the right ones.
1237         */
1238
1239         const uint16_t selected_channels = _channel_selector.get_selected_channels();
1240         bool changed = false;
1241
1242         no_redraw = true;
1243
1244         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1245
1246                 for (uint32_t chn = 0; chn < 16; ++chn) {
1247                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1248                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1249
1250                         if (!track) {
1251                                 continue;
1252                         }
1253
1254                         if ((selected_channels & (0x0001 << chn)) == 0) {
1255                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1256                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1257                                 */
1258                                 changed = track->set_marked_for_display (false) || changed;
1259                         } else {
1260                                 changed = track->set_marked_for_display (true) || changed;
1261                         }
1262                 }
1263         }
1264
1265         no_redraw = false;
1266
1267         /* TODO: Bender, Pressure */
1268
1269         /* invalidate the controller menu, so that we rebuild it next time */
1270         _controller_menu_map.clear ();
1271         delete controller_menu;
1272         controller_menu = 0;
1273
1274         if (changed) {
1275                 request_redraw ();
1276         }
1277 }
1278
1279 Gtk::CheckMenuItem*
1280 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1281 {
1282         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1283         if (m) {
1284                 return m;
1285         }
1286
1287         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1288         if (i != _controller_menu_map.end()) {
1289                 return i->second;
1290         }
1291
1292         i = _channel_command_menu_map.find (param);
1293         if (i != _channel_command_menu_map.end()) {
1294                 return i->second;
1295         }
1296
1297         return 0;
1298 }
1299
1300 boost::shared_ptr<MidiRegion>
1301 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1302 {
1303         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1304
1305         real_editor->begin_reversible_command (Operations::create_region);
1306         playlist()->clear_changes ();
1307
1308         real_editor->snap_to (pos, 0);
1309
1310         boost::shared_ptr<Source> src = _session->create_midi_source_for_session (
1311                 view()->trackview().track().get(), view()->trackview().track()->name());
1312         PropertyList plist;
1313
1314         plist.add (ARDOUR::Properties::start, 0);
1315         plist.add (ARDOUR::Properties::length, length);
1316         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1317
1318         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1319
1320         playlist()->add_region (region, pos);
1321         _session->add_command (new StatefulDiffCommand (playlist()));
1322
1323         if (commit) {
1324                 real_editor->commit_reversible_command ();
1325         }
1326
1327         return boost::dynamic_pointer_cast<MidiRegion>(region);
1328 }
1329
1330 void
1331 MidiTimeAxisView::ensure_step_editor ()
1332 {
1333         if (!_step_editor) {
1334                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1335         }
1336 }
1337
1338 void
1339 MidiTimeAxisView::start_step_editing ()
1340 {
1341         ensure_step_editor ();
1342         _step_editor->start_step_editing ();
1343
1344 }
1345 void
1346 MidiTimeAxisView::stop_step_editing ()
1347 {
1348         if (_step_editor) {
1349                 _step_editor->stop_step_editing ();
1350         }
1351 }
1352
1353
1354 /** @return channel (counted from 0) to add an event to, based on the current setting
1355  *  of the channel selector.
1356  */
1357 uint8_t
1358 MidiTimeAxisView::get_channel_for_add () const
1359 {
1360         uint16_t const chn_mask = _channel_selector.get_selected_channels ();
1361         int chn_cnt = 0;
1362         uint8_t channel = 0;
1363
1364         /* pick the highest selected channel, unless all channels are selected,
1365            which is interpreted to mean channel 1 (zero)
1366         */
1367
1368         for (uint16_t i = 0; i < 16; ++i) {
1369                 if (chn_mask & (1<<i)) {
1370                         channel = i;
1371                         chn_cnt++;
1372                 }
1373         }
1374
1375         if (chn_cnt == 16) {
1376                 channel = 0;
1377         }
1378
1379         return channel;
1380 }
1381
1382 void
1383 MidiTimeAxisView::note_range_changed ()
1384 {
1385         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1386         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1387 }
1388
1389 void
1390 MidiTimeAxisView::contents_height_changed ()
1391 {
1392         _range_scroomer->set_size_request (-1, _view->child_height ());
1393 }