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