2 Copyright (C) 2000 Paul Davis
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.
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.
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.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/profile.h"
54 #include "ardour/region.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_object.h"
59 #include "ardour/source.h"
60 #include "ardour/track.h"
61 #include "ardour/types.h"
63 #include "ardour_ui.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
88 #include "note_base.h"
90 #include "ardour/midi_track.h"
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
102 // Minimum height at which a control is displayed
103 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
104 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
106 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
107 : AxisView(sess) // virtually inherited
108 , RouteTimeAxisView(ed, sess, canvas)
109 , _ignore_signals(false)
111 , _piano_roll_header(0)
112 , _note_mode(Sustained)
114 , _percussion_mode_item(0)
115 , _color_mode(MeterColors)
116 , _meter_color_mode_item(0)
117 , _channel_color_mode_item(0)
118 , _track_color_mode_item(0)
119 , _channel_selector (0)
120 , _step_edit_item (0)
121 , controller_menu (0)
127 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
131 _view = new MidiStreamView (*this);
134 _piano_roll_header = new PianoRollHeader(*midi_view());
135 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
136 _range_scroomer->DoubleClicked.connect (
137 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
138 MidiStreamView::ContentsRange, false));
141 /* This next call will result in our height being set up, so it must come after
142 the creation of the piano roll / range scroomer as their visibility is set up
145 RouteTimeAxisView::set_route (rt);
147 _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
149 subplugin_menu.set_name ("ArdourContextMenu");
151 if (!gui_property ("note-range-min").empty ()) {
152 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
153 atoi (gui_property ("note-range-max").c_str()),
157 midi_view()->NoteRangeChanged.connect (
158 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
159 _view->ContentsHeightChanged.connect (
160 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
162 ignore_toggle = false;
164 if (is_midi_track()) {
165 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
166 time_axis_frame.set_name ("MidiTimeAxisViewControlsBaseUnselected");
167 _note_mode = midi_track()->note_mode();
168 } else { // MIDI bus (which doesn't exist yet..)
169 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
170 time_axis_frame.set_name ("MidiBusControlsBaseUnselected");
173 /* if set_state above didn't create a gain automation child, we need to make one */
174 if (automation_child (GainAutomation) == 0) {
175 create_automation_child (GainAutomation, false);
178 /* if set_state above didn't create a mute automation child, we need to make one */
179 if (automation_child (MuteAutomation) == 0) {
180 create_automation_child (MuteAutomation, false);
183 if (_route->panner_shell()) {
184 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
187 /* map current state of the route */
188 ensure_pan_views (false);
190 processors_changed (RouteProcessorChange ());
192 _route->processors_changed.connect (*this, invalidator (*this),
193 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
197 _piano_roll_header->SetNoteSelection.connect (
198 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
199 _piano_roll_header->AddNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
201 _piano_roll_header->ExtendNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
203 _piano_roll_header->ToggleNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
206 /* Suspend updates of the StreamView during scroomer drags to speed things up */
207 _range_scroomer->DragStarting.connect (
208 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
209 _range_scroomer->DragFinishing.connect (
210 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
212 /* Put the scroomer and the keyboard in a VBox with a padding
213 label so that they can be reduced in height for stacked-view
217 HSeparator* separator = manage (new HSeparator());
218 separator->set_name("TrackSeparator");
219 separator->set_size_request(-1, 1);
222 VBox* v = manage (new VBox);
223 HBox* h = manage (new HBox);
224 h->pack_end (*_piano_roll_header);
225 h->pack_end (*_range_scroomer);
226 v->pack_start (*separator, false, false);
227 v->pack_start (*h, true, true);
230 top_hbox.remove(scroomer_placeholder);
231 time_axis_hbox.pack_end(*v, false, false, 0);
232 midi_scroomer_size_group->add_widget (*v);
234 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
235 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
236 controls_base_selected_name = "MidiTrackControlsBaseSelected";
237 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
239 midi_view()->NoteRangeChanged.connect (
240 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
242 /* ask for notifications of any new RegionViews */
243 _view->RegionViewAdded.connect (
244 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
246 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
247 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
249 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
250 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
252 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
253 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
255 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
256 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
259 playback_channel_mode_changed ();
260 capture_channel_mode_changed ();
262 if (!_editor.have_idled()) {
263 /* first idle will do what we need */
269 typedef MIDI::Name::MidiPatchManager PatchManager;
271 PatchManager& patch_manager = PatchManager::instance();
273 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
274 m != patch_manager.devices_by_manufacturer().end(); ++m) {
275 Menu* menu = Gtk::manage(new Menu);
276 Menu_Helpers::MenuList& items = menu->items();
278 // Build manufacturer submenu
279 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
280 n != m->second.end(); ++n) {
281 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
283 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
286 items.push_back(elem);
289 // Add manufacturer submenu to selector
290 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
293 if (gui_property (X_("midnam-model-name")).empty()) {
294 set_gui_property (X_("midnam-model-name"), "Generic");
297 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
298 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
300 set_gui_property (X_("midnam-custom-device-mode"),
301 *device_names->custom_device_mode_names().begin());
305 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
306 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
308 _midi_controls_box.set_homogeneous(false);
309 _midi_controls_box.set_border_width (2);
311 _channel_status_box.set_homogeneous (false);
312 _channel_status_box.set_spacing (4);
314 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
315 channel_selector_button->set_name ("route button");
316 ARDOUR_UI::instance()->set_tip (channel_selector_button, _("Click to edit channel settings"));
318 // Insert expanding space labels to get full width justification
319 _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
320 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
321 _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
322 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
323 _channel_status_box.pack_end (*channel_selector_button, false, false);
324 _channel_status_box.show_all ();
326 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
328 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
330 if (!patch_manager.all_models().empty()) {
332 _midnam_model_selector.show ();
333 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
335 _midnam_custom_device_mode_selector.show ();
337 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
340 model_changed(gui_property(X_("midnam-model-name")));
341 custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
343 controls_vbox.pack_start(_midi_controls_box, false, false);
345 const string color_mode = gui_property ("color-mode");
346 if (!color_mode.empty()) {
347 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
348 if (_channel_selector && _color_mode == ChannelColors) {
349 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
353 set_color_mode (_color_mode, true, false);
355 const string note_mode = gui_property ("note-mode");
356 if (!note_mode.empty()) {
357 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
358 if (_percussion_mode_item) {
359 _percussion_mode_item->set_active (_note_mode == Percussive);
363 /* Look for any GUI object state nodes that represent automation children
364 * that should exist, and create the children.
367 const list<string> gui_ids = gui_object_state().all_ids ();
368 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
371 Evoral::Parameter parameter (0, 0, 0);
373 bool const p = AutomationTimeAxisView::parse_state_id (
374 *i, route_id, has_parameter, parameter);
375 if (p && route_id == _route->id () && has_parameter) {
376 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
377 create_automation_child (parameter, string_is_affirmative (visible));
383 MidiTimeAxisView::first_idle ()
390 MidiTimeAxisView::~MidiTimeAxisView ()
392 delete _channel_selector;
394 delete _piano_roll_header;
395 _piano_roll_header = 0;
397 delete _range_scroomer;
400 delete controller_menu;
405 MidiTimeAxisView::check_step_edit ()
407 ensure_step_editor ();
408 _step_editor->check_step_edit ();
412 MidiTimeAxisView::model_changed(const std::string& model)
414 set_gui_property (X_("midnam-model-name"), model);
416 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
417 .custom_device_mode_names_by_model(model);
419 _midnam_model_selector.set_text(model);
420 _midnam_custom_device_mode_selector.clear_items();
422 for (std::list<std::string>::const_iterator i = device_modes.begin();
423 i != device_modes.end(); ++i) {
424 _midnam_custom_device_mode_selector.AddMenuElem(
425 Gtk::Menu_Helpers::MenuElem(
426 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
430 if (!device_modes.empty()) {
431 custom_device_mode_changed(device_modes.front());
434 if (device_modes.size() > 1) {
435 _midnam_custom_device_mode_selector.show();
437 _midnam_custom_device_mode_selector.hide();
440 if (device_modes.size() > 0) {
441 _route->instrument_info().set_external_instrument (model, device_modes.front());
443 _route->instrument_info().set_external_instrument (model, "");
446 // Rebuild controller menu
447 _controller_menu_map.clear ();
448 delete controller_menu;
450 build_automation_action_menu(false);
454 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
456 const std::string model = gui_property (X_("midnam-model-name"));
458 set_gui_property (X_("midnam-custom-device-mode"), mode);
459 _midnam_custom_device_mode_selector.set_text(mode);
460 _route->instrument_info().set_external_instrument (model, mode);
464 MidiTimeAxisView::midi_view()
466 return dynamic_cast<MidiStreamView*>(_view);
470 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
472 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
473 _midi_controls_box.show ();
475 _midi_controls_box.hide();
478 if (h >= KEYBOARD_MIN_HEIGHT) {
479 if (is_track() && _range_scroomer) {
480 _range_scroomer->show();
482 if (is_track() && _piano_roll_header) {
483 _piano_roll_header->show();
486 if (is_track() && _range_scroomer) {
487 _range_scroomer->hide();
489 if (is_track() && _piano_roll_header) {
490 _piano_roll_header->hide();
494 /* We need to do this after changing visibility of our stuff, as it will
495 eventually trigger a call to Editor::reset_controls_layout_width(),
496 which needs to know if we have just shown or hidden a scroomer /
499 RouteTimeAxisView::set_height (h, m);
503 MidiTimeAxisView::append_extra_display_menu_items ()
505 using namespace Menu_Helpers;
507 MenuList& items = display_menu->items();
510 Menu *range_menu = manage(new Menu);
511 MenuList& range_items = range_menu->items();
512 range_menu->set_name ("ArdourContextMenu");
514 range_items.push_back (
515 MenuElem (_("Show Full Range"),
516 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
517 MidiStreamView::FullRange, true)));
519 range_items.push_back (
520 MenuElem (_("Fit Contents"),
521 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
522 MidiStreamView::ContentsRange, true)));
524 items.push_back (MenuElem (_("Note Range"), *range_menu));
525 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
526 items.push_back (MenuElem (_("Channel Selector"),
527 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
529 color_mode_menu = build_color_mode_menu();
530 if (color_mode_menu) {
531 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
534 items.push_back (SeparatorElem ());
538 MidiTimeAxisView::toggle_channel_selector ()
540 if (!_channel_selector) {
541 _channel_selector = new MidiChannelSelectorWindow (midi_track());
543 if (_color_mode == ChannelColors) {
544 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
546 _channel_selector->set_default_channel_color ();
549 _channel_selector->show_all ();
551 _channel_selector->cycle_visibility ();
556 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
558 using namespace Menu_Helpers;
560 /* If we have a controller menu, we need to detach it before
561 RouteTimeAxis::build_automation_action_menu destroys the
562 menu it is attached to. Otherwise GTK destroys
563 controller_menu's gobj, meaning that it can't be reattached
564 below. See bug #3134.
567 if (controller_menu) {
568 detach_menu (*controller_menu);
571 _channel_command_menu_map.clear ();
572 RouteTimeAxisView::build_automation_action_menu (for_selection);
574 MenuList& automation_items = automation_action_menu->items();
576 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
578 if (selected_channels != 0) {
580 automation_items.push_back (SeparatorElem());
582 /* these 2 MIDI "command" types are semantically more like automation
583 than note data, but they are not MIDI controllers. We give them
584 special status in this menu, since they will not show up in the
585 controller list and anyone who actually knows something about MIDI
586 (!) would not expect to find them there.
589 add_channel_command_menu_item (
590 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
591 automation_items.back().set_sensitive (
592 !for_selection || _editor.get_selection().tracks.size() == 1);
593 add_channel_command_menu_item (
594 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
595 automation_items.back().set_sensitive (
596 !for_selection || _editor.get_selection().tracks.size() == 1);
598 /* now all MIDI controllers. Always offer the possibility that we will
599 rebuild the controllers menu since it might need to be updated after
600 a channel mode change or other change. Also detach it first in case
601 it has been used anywhere else.
604 build_controller_menu ();
606 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
607 automation_items.back().set_sensitive (
608 !for_selection || _editor.get_selection().tracks.size() == 1);
610 automation_items.push_back (
611 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
612 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
617 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
619 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
621 for (uint8_t chn = 0; chn < 16; chn++) {
622 if (selected_channels & (0x0001 << chn)) {
624 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
625 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
628 menu->set_active (yn);
635 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
637 AutomationType auto_type,
640 using namespace Menu_Helpers;
642 /* count the number of selected channels because we will build a different menu
643 structure if there is more than 1 selected.
646 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
649 for (uint8_t chn = 0; chn < 16; chn++) {
650 if (selected_channels & (0x0001 << chn)) {
659 /* multiple channels - create a submenu, with 1 item per channel */
661 Menu* chn_menu = manage (new Menu);
662 MenuList& chn_items (chn_menu->items());
663 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
665 /* add a couple of items to hide/show all of them */
667 chn_items.push_back (
668 MenuElem (_("Hide all channels"),
669 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
670 false, param_without_channel)));
671 chn_items.push_back (
672 MenuElem (_("Show all channels"),
673 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
674 true, param_without_channel)));
676 for (uint8_t chn = 0; chn < 16; chn++) {
677 if (selected_channels & (0x0001 << chn)) {
679 /* for each selected channel, add a menu item for this controller */
681 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
682 chn_items.push_back (
683 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
684 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
685 fully_qualified_param)));
687 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
688 bool visible = false;
691 if (track->marked_for_display()) {
696 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
697 _channel_command_menu_map[fully_qualified_param] = cmi;
698 cmi->set_active (visible);
702 /* now create an item in the parent menu that has the per-channel list as a submenu */
704 items.push_back (MenuElem (label, *chn_menu));
708 /* just one channel - create a single menu item for this command+channel combination*/
710 for (uint8_t chn = 0; chn < 16; chn++) {
711 if (selected_channels & (0x0001 << chn)) {
713 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
715 CheckMenuElem (label,
716 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
717 fully_qualified_param)));
719 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
720 bool visible = false;
723 if (track->marked_for_display()) {
728 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
729 _channel_command_menu_map[fully_qualified_param] = cmi;
730 cmi->set_active (visible);
732 /* one channel only */
739 /** Add a single menu item for a controller on one channel. */
741 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
743 const std::string& name)
745 using namespace Menu_Helpers;
747 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
748 for (uint8_t chn = 0; chn < 16; chn++) {
749 if (selected_channels & (0x0001 << chn)) {
751 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
752 ctl_items.push_back (
754 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
756 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
757 fully_qualified_param)));
758 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
760 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
761 fully_qualified_param);
763 bool visible = false;
765 if (track->marked_for_display()) {
770 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
771 _controller_menu_map[fully_qualified_param] = cmi;
772 cmi->set_active (visible);
774 /* one channel only */
780 /** Add a submenu with 1 item per channel for a controller on many channels. */
782 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
784 const std::string& name)
786 using namespace Menu_Helpers;
788 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
790 Menu* chn_menu = manage (new Menu);
791 MenuList& chn_items (chn_menu->items());
793 /* add a couple of items to hide/show this controller on all channels */
795 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
796 chn_items.push_back (
797 MenuElem (_("Hide all channels"),
798 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
799 false, param_without_channel)));
800 chn_items.push_back (
801 MenuElem (_("Show all channels"),
802 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
803 true, param_without_channel)));
805 for (uint8_t chn = 0; chn < 16; chn++) {
806 if (selected_channels & (0x0001 << chn)) {
808 /* for each selected channel, add a menu item for this controller */
810 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
811 chn_items.push_back (
812 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
813 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
814 fully_qualified_param)));
816 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
817 fully_qualified_param);
818 bool visible = false;
821 if (track->marked_for_display()) {
826 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
827 _controller_menu_map[fully_qualified_param] = cmi;
828 cmi->set_active (visible);
832 /* add the per-channel menu to the list of controllers, with the name of the controller */
833 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
835 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
838 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
839 MidiTimeAxisView::get_device_mode()
841 using namespace MIDI::Name;
843 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
845 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
848 return device_names->custom_device_mode_by_name(
849 gui_property (X_("midnam-custom-device-mode")));
852 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
853 MidiTimeAxisView::get_device_names()
855 using namespace MIDI::Name;
857 const std::string model = gui_property (X_("midnam-model-name"));
859 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
860 .document_by_model(model);
862 return midnam->master_device_names(model);
864 return boost::shared_ptr<MasterDeviceNames>();
869 MidiTimeAxisView::build_controller_menu ()
871 using namespace Menu_Helpers;
873 if (controller_menu) {
874 /* it exists and has not been invalidated by a channel mode change */
878 controller_menu = new Menu; // explicitly managed by us
879 MenuList& items (controller_menu->items());
881 /* create several "top level" menu items for sets of controllers (16 at a
882 time), and populate each one with a submenu for each controller+channel
883 combination covering the currently selected channels for this track
886 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
888 /* count the number of selected channels because we will build a different menu
889 structure if there is more than 1 selected.
893 for (uint8_t chn = 0; chn < 16; chn++) {
894 if (selected_channels & (0x0001 << chn)) {
901 using namespace MIDI::Name;
902 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
904 if (device_names && !device_names->controls().empty()) {
905 /* Controllers names available in midnam file, generate fancy menu */
906 unsigned n_items = 0;
907 unsigned n_groups = 0;
909 /* TODO: This is not correct, should look up the currently applicable ControlNameList
910 and only build a menu for that one. */
911 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
912 l != device_names->controls().end(); ++l) {
913 boost::shared_ptr<ControlNameList> name_list = l->second;
914 Menu* ctl_menu = NULL;
916 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
917 c != name_list->controls().end();) {
918 const uint16_t ctl = c->second->number();
919 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
920 /* Skip bank select controllers since they're handled specially */
922 /* Create a new submenu */
923 ctl_menu = manage (new Menu);
926 MenuList& ctl_items (ctl_menu->items());
928 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
930 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
935 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
936 /* Submenu has 16 items or we're done, add it to controller menu and reset */
938 MenuElem(string_compose(_("Controllers %1-%2"),
939 (16 * n_groups), (16 * n_groups) + n_items - 1),
948 /* No controllers names, generate generic numeric menu */
949 for (int i = 0; i < 127; i += 16) {
950 Menu* ctl_menu = manage (new Menu);
951 MenuList& ctl_items (ctl_menu->items());
953 for (int ctl = i; ctl < i+16; ++ctl) {
954 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
955 /* Skip bank select controllers since they're handled specially */
960 add_multi_channel_controller_item(
961 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
963 add_single_channel_controller_item(
964 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
968 /* Add submenu for this block of controllers to controller menu */
970 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
977 MidiTimeAxisView::build_note_mode_menu()
979 using namespace Menu_Helpers;
981 Menu* mode_menu = manage (new Menu);
982 MenuList& items = mode_menu->items();
983 mode_menu->set_name ("ArdourContextMenu");
985 RadioMenuItem::Group mode_group;
987 RadioMenuElem (mode_group,_("Sustained"),
988 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
990 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
991 _note_mode_item->set_active(_note_mode == Sustained);
994 RadioMenuElem (mode_group, _("Percussive"),
995 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
997 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
998 _percussion_mode_item->set_active(_note_mode == Percussive);
1004 MidiTimeAxisView::build_color_mode_menu()
1006 using namespace Menu_Helpers;
1008 Menu* mode_menu = manage (new Menu);
1009 MenuList& items = mode_menu->items();
1010 mode_menu->set_name ("ArdourContextMenu");
1012 RadioMenuItem::Group mode_group;
1014 RadioMenuElem (mode_group, _("Meter Colors"),
1015 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1016 MeterColors, false, true, true)));
1017 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1018 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1021 RadioMenuElem (mode_group, _("Channel Colors"),
1022 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1023 ChannelColors, false, true, true)));
1024 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1025 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1028 RadioMenuElem (mode_group, _("Track Color"),
1029 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1030 TrackColor, false, true, true)));
1031 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1032 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1038 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1040 if (apply_to_selection) {
1041 _editor.get_selection().tracks.foreach_midi_time_axis (
1042 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1044 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1046 midi_track()->set_note_mode(mode);
1047 set_gui_property ("note-mode", enum_2_string(_note_mode));
1048 _view->redisplay_track();
1054 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1056 if (apply_to_selection) {
1057 _editor.get_selection().tracks.foreach_midi_time_axis (
1058 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1060 if (_color_mode == mode && !force) {
1064 if (_channel_selector) {
1065 if (mode == ChannelColors) {
1066 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1068 _channel_selector->set_default_channel_color();
1073 set_gui_property ("color-mode", enum_2_string(_color_mode));
1075 _view->redisplay_track();
1081 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1083 if (apply_to_selection) {
1084 _editor.get_selection().tracks.foreach_midi_time_axis (
1085 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1087 if (!_ignore_signals) {
1088 midi_view()->set_note_range(range);
1094 MidiTimeAxisView::update_range()
1096 MidiGhostRegion* mgr;
1098 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1099 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1100 mgr->update_range();
1106 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1108 using namespace MIDI::Name;
1110 if (apply_to_selection) {
1111 _editor.get_selection().tracks.foreach_midi_time_axis (
1112 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1115 // Show existing automation
1116 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1118 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1119 create_automation_child(*i, true);
1122 // Show automation for all controllers named in midnam file
1123 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1124 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1125 device_names && !device_names->controls().empty()) {
1126 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1127 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1128 for (uint32_t chn = 0; chn < 16; ++chn) {
1129 if ((selected_channels & (0x0001 << chn)) == 0) {
1130 // Channel not in use
1134 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1140 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1141 chan_names->control_list_name());
1142 if (!control_names) {
1146 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1147 c != control_names->controls().end();
1149 const uint16_t ctl = c->second->number();
1150 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1151 /* Skip bank select controllers since they're handled specially */
1152 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1153 create_automation_child(param, true);
1160 RouteTimeAxisView::show_all_automation ();
1165 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1167 if (apply_to_selection) {
1168 _editor.get_selection().tracks.foreach_midi_time_axis (
1169 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1172 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1174 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1175 create_automation_child (*i, true);
1179 RouteTimeAxisView::show_existing_automation ();
1183 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1186 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1188 if (param.type() == NullAutomation) {
1192 AutomationTracks::iterator existing = _automation_tracks.find (param);
1194 if (existing != _automation_tracks.end()) {
1196 /* automation track created because we had existing data for
1197 * the processor, but visibility may need to be controlled
1198 * since it will have been set visible by default.
1201 existing->second->set_marked_for_display (show);
1210 boost::shared_ptr<AutomationTimeAxisView> track;
1211 boost::shared_ptr<AutomationControl> control;
1214 switch (param.type()) {
1216 case GainAutomation:
1217 create_gain_automation_child (param, show);
1220 case MuteAutomation:
1221 create_mute_automation_child (param, show);
1224 case PluginAutomation:
1225 /* handled elsewhere */
1228 case MidiCCAutomation:
1229 case MidiPgmChangeAutomation:
1230 case MidiPitchBenderAutomation:
1231 case MidiChannelPressureAutomation:
1232 case MidiSystemExclusiveAutomation:
1233 /* These controllers are region "automation" - they are owned
1234 * by regions (and their MidiModels), not by the track. As a
1235 * result there is no AutomationList/Line for the track, but we create
1236 * a controller for the user to write immediate events, so the editor
1237 * can act as a control surface for the present MIDI controllers.
1239 * TODO: Record manipulation of the controller to regions?
1242 control = _route->automation_control(param, true);
1243 track.reset (new AutomationTimeAxisView (
1246 control ? _route : boost::shared_ptr<Automatable> (),
1253 _route->describe_parameter(param)));
1256 _view->foreach_regionview (
1257 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1260 add_automation_child (param, track, show);
1263 case PanWidthAutomation:
1264 case PanElevationAutomation:
1265 case PanAzimuthAutomation:
1266 ensure_pan_views (show);
1270 error << "MidiTimeAxisView: unknown automation child "
1271 << EventTypeMap::instance().to_symbol(param) << endmsg;
1276 MidiTimeAxisView::route_active_changed ()
1278 RouteUI::route_active_changed ();
1281 if (_route->active()) {
1282 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1283 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1284 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1285 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1287 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1288 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1289 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1290 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1293 if (_route->active()) {
1294 controls_ebox.set_name ("BusControlsBaseUnselected");
1295 time_axis_frame.set_name ("BusControlsBaseUnselected");
1296 controls_base_selected_name = "BusControlsBaseSelected";
1297 controls_base_unselected_name = "BusControlsBaseUnselected";
1299 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1300 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1301 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1302 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1308 MidiTimeAxisView::set_note_selection (uint8_t note)
1310 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1312 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1314 if (_view->num_selected_regionviews() == 0) {
1315 _view->foreach_regionview (
1316 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1319 _view->foreach_selected_regionview (
1320 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1324 _editor.commit_reversible_selection_op();
1328 MidiTimeAxisView::add_note_selection (uint8_t note)
1330 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1332 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1334 if (_view->num_selected_regionviews() == 0) {
1335 _view->foreach_regionview (
1336 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1339 _view->foreach_selected_regionview (
1340 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1344 _editor.commit_reversible_selection_op();
1348 MidiTimeAxisView::extend_note_selection (uint8_t note)
1350 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1352 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1354 if (_view->num_selected_regionviews() == 0) {
1355 _view->foreach_regionview (
1356 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1359 _view->foreach_selected_regionview (
1360 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1364 _editor.commit_reversible_selection_op();
1368 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1370 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1372 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1374 if (_view->num_selected_regionviews() == 0) {
1375 _view->foreach_regionview (
1376 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1379 _view->foreach_selected_regionview (
1380 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1384 _editor.commit_reversible_selection_op();
1388 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1390 _view->foreach_regionview (
1391 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1395 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1397 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1401 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1403 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1407 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1409 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1413 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1415 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1419 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1421 Evoral::Sequence<Evoral::Beats>::Notes selected;
1422 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1424 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1426 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1427 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1428 notes.insert (*sel_it);
1431 if (!notes.empty()) {
1432 selection.push_back (make_pair ((rv)->region()->id(), notes));
1437 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1439 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1443 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1444 bool changed = false;
1448 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1450 for (uint32_t chn = 0; chn < 16; ++chn) {
1451 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1452 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1458 if ((selected_channels & (0x0001 << chn)) == 0) {
1459 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1460 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1462 changed = track->set_marked_for_display (false) || changed;
1464 changed = track->set_marked_for_display (true) || changed;
1471 /* TODO: Bender, Pressure */
1473 /* invalidate the controller menu, so that we rebuild it next time */
1474 _controller_menu_map.clear ();
1475 delete controller_menu;
1476 controller_menu = 0;
1484 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1486 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1491 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1492 if (i != _controller_menu_map.end()) {
1496 i = _channel_command_menu_map.find (param);
1497 if (i != _channel_command_menu_map.end()) {
1504 boost::shared_ptr<MidiRegion>
1505 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1507 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1509 real_editor->begin_reversible_command (Operations::create_region);
1510 playlist()->clear_changes ();
1512 real_editor->snap_to (pos, RoundNearest);
1514 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1517 plist.add (ARDOUR::Properties::start, 0);
1518 plist.add (ARDOUR::Properties::length, length);
1519 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1521 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1523 playlist()->add_region (region, pos);
1524 _session->add_command (new StatefulDiffCommand (playlist()));
1527 real_editor->commit_reversible_command ();
1530 return boost::dynamic_pointer_cast<MidiRegion>(region);
1534 MidiTimeAxisView::ensure_step_editor ()
1536 if (!_step_editor) {
1537 _step_editor = new StepEditor (_editor, midi_track(), *this);
1542 MidiTimeAxisView::start_step_editing ()
1544 ensure_step_editor ();
1545 _step_editor->start_step_editing ();
1549 MidiTimeAxisView::stop_step_editing ()
1552 _step_editor->stop_step_editing ();
1556 /** @return channel (counted from 0) to add an event to, based on the current setting
1557 * of the channel selector.
1560 MidiTimeAxisView::get_channel_for_add () const
1562 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1564 uint8_t channel = 0;
1566 /* pick the highest selected channel, unless all channels are selected,
1567 which is interpreted to mean channel 1 (zero)
1570 for (uint16_t i = 0; i < 16; ++i) {
1571 if (chn_mask & (1<<i)) {
1577 if (chn_cnt == 16) {
1585 MidiTimeAxisView::note_range_changed ()
1587 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1588 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1592 MidiTimeAxisView::contents_height_changed ()
1594 _range_scroomer->queue_resize ();
1598 MidiTimeAxisView::playback_channel_mode_changed ()
1600 switch (midi_track()->get_playback_channel_mode()) {
1602 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1604 case FilterChannels:
1605 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1608 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1614 MidiTimeAxisView::capture_channel_mode_changed ()
1616 switch (midi_track()->get_capture_channel_mode()) {
1618 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1620 case FilterChannels:
1621 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1624 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1630 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
1632 if (!_editor.internal_editing()) {
1633 // Non-internal paste, paste regions like any other route
1634 return RouteTimeAxisView::paste(pos, selection, ctx);
1637 return midi_view()->paste(pos, selection, ctx);