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