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