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 /* fixed sized labels to prevent silly nonsense (though obviously,
319 * they cause their own too)
321 set_size_request_to_display_given_text(_playback_channel_status, "Play: somemo", 2, 2); // TODO use _("Play: all/some")
322 set_size_request_to_display_given_text(_capture_channel_status, "Rec: somemo", 2, 2); // TODO use _("Rec: all/some")
324 _channel_status_box.pack_start (_playback_channel_status, false, false);
325 _channel_status_box.pack_start (_capture_channel_status, false, false);
326 _channel_status_box.pack_end (*channel_selector_button, false, false);
327 _channel_status_box.show_all ();
329 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
331 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
333 if (!patch_manager.all_models().empty()) {
335 _midnam_model_selector.show ();
336 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
338 _midnam_custom_device_mode_selector.show ();
340 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
343 model_changed(gui_property(X_("midnam-model-name")));
344 custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
346 controls_vbox.pack_start(_midi_controls_box, false, false);
348 const string color_mode = gui_property ("color-mode");
349 if (!color_mode.empty()) {
350 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
351 if (_channel_selector && _color_mode == ChannelColors) {
352 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
356 set_color_mode (_color_mode, true, false);
358 const string note_mode = gui_property ("note-mode");
359 if (!note_mode.empty()) {
360 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
361 if (_percussion_mode_item) {
362 _percussion_mode_item->set_active (_note_mode == Percussive);
366 /* Look for any GUI object state nodes that represent automation children
367 * that should exist, and create the children.
370 const list<string> gui_ids = gui_object_state().all_ids ();
371 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
374 Evoral::Parameter parameter (0, 0, 0);
376 bool const p = AutomationTimeAxisView::parse_state_id (
377 *i, route_id, has_parameter, parameter);
378 if (p && route_id == _route->id () && has_parameter) {
379 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
380 create_automation_child (parameter, string_is_affirmative (visible));
386 MidiTimeAxisView::first_idle ()
393 MidiTimeAxisView::~MidiTimeAxisView ()
395 delete _channel_selector;
397 delete _piano_roll_header;
398 _piano_roll_header = 0;
400 delete _range_scroomer;
403 delete controller_menu;
408 MidiTimeAxisView::check_step_edit ()
410 ensure_step_editor ();
411 _step_editor->check_step_edit ();
415 MidiTimeAxisView::model_changed(const std::string& model)
417 set_gui_property (X_("midnam-model-name"), model);
419 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
420 .custom_device_mode_names_by_model(model);
422 _midnam_model_selector.set_text(model);
423 _midnam_custom_device_mode_selector.clear_items();
425 for (std::list<std::string>::const_iterator i = device_modes.begin();
426 i != device_modes.end(); ++i) {
427 _midnam_custom_device_mode_selector.AddMenuElem(
428 Gtk::Menu_Helpers::MenuElem(
429 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
433 if (!device_modes.empty()) {
434 custom_device_mode_changed(device_modes.front());
437 if (device_modes.size() > 1) {
438 _midnam_custom_device_mode_selector.show();
440 _midnam_custom_device_mode_selector.hide();
443 if (device_modes.size() > 0) {
444 _route->instrument_info().set_external_instrument (model, device_modes.front());
446 _route->instrument_info().set_external_instrument (model, "");
449 // Rebuild controller menu
450 _controller_menu_map.clear ();
451 delete controller_menu;
453 build_automation_action_menu(false);
457 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
459 const std::string model = gui_property (X_("midnam-model-name"));
461 set_gui_property (X_("midnam-custom-device-mode"), mode);
462 _midnam_custom_device_mode_selector.set_text(mode);
463 _route->instrument_info().set_external_instrument (model, mode);
467 MidiTimeAxisView::midi_view()
469 return dynamic_cast<MidiStreamView*>(_view);
473 MidiTimeAxisView::set_height (uint32_t h)
475 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
476 _midi_controls_box.show ();
478 _midi_controls_box.hide();
481 if (h >= KEYBOARD_MIN_HEIGHT) {
482 if (is_track() && _range_scroomer) {
483 _range_scroomer->show();
485 if (is_track() && _piano_roll_header) {
486 _piano_roll_header->show();
489 if (is_track() && _range_scroomer) {
490 _range_scroomer->hide();
492 if (is_track() && _piano_roll_header) {
493 _piano_roll_header->hide();
497 /* We need to do this after changing visibility of our stuff, as it will
498 eventually trigger a call to Editor::reset_controls_layout_width(),
499 which needs to know if we have just shown or hidden a scroomer /
502 RouteTimeAxisView::set_height (h);
506 MidiTimeAxisView::append_extra_display_menu_items ()
508 using namespace Menu_Helpers;
510 MenuList& items = display_menu->items();
513 Menu *range_menu = manage(new Menu);
514 MenuList& range_items = range_menu->items();
515 range_menu->set_name ("ArdourContextMenu");
517 range_items.push_back (
518 MenuElem (_("Show Full Range"),
519 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
520 MidiStreamView::FullRange, true)));
522 range_items.push_back (
523 MenuElem (_("Fit Contents"),
524 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
525 MidiStreamView::ContentsRange, true)));
527 items.push_back (MenuElem (_("Note Range"), *range_menu));
528 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
529 items.push_back (MenuElem (_("Channel Selector"),
530 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
532 color_mode_menu = build_color_mode_menu();
533 if (color_mode_menu) {
534 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
537 items.push_back (SeparatorElem ());
541 MidiTimeAxisView::toggle_channel_selector ()
543 if (!_channel_selector) {
544 _channel_selector = new MidiChannelSelectorWindow (midi_track());
546 if (_color_mode == ChannelColors) {
547 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
549 _channel_selector->set_default_channel_color ();
552 _channel_selector->show_all ();
554 _channel_selector->cycle_visibility ();
559 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
561 using namespace Menu_Helpers;
563 /* If we have a controller menu, we need to detach it before
564 RouteTimeAxis::build_automation_action_menu destroys the
565 menu it is attached to. Otherwise GTK destroys
566 controller_menu's gobj, meaning that it can't be reattached
567 below. See bug #3134.
570 if (controller_menu) {
571 detach_menu (*controller_menu);
574 _channel_command_menu_map.clear ();
575 RouteTimeAxisView::build_automation_action_menu (for_selection);
577 MenuList& automation_items = automation_action_menu->items();
579 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
581 if (selected_channels != 0) {
583 automation_items.push_back (SeparatorElem());
585 /* these 2 MIDI "command" types are semantically more like automation
586 than note data, but they are not MIDI controllers. We give them
587 special status in this menu, since they will not show up in the
588 controller list and anyone who actually knows something about MIDI
589 (!) would not expect to find them there.
592 add_channel_command_menu_item (
593 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
594 automation_items.back().set_sensitive (
595 !for_selection || _editor.get_selection().tracks.size() == 1);
596 add_channel_command_menu_item (
597 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
598 automation_items.back().set_sensitive (
599 !for_selection || _editor.get_selection().tracks.size() == 1);
601 /* now all MIDI controllers. Always offer the possibility that we will
602 rebuild the controllers menu since it might need to be updated after
603 a channel mode change or other change. Also detach it first in case
604 it has been used anywhere else.
607 build_controller_menu ();
609 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
610 automation_items.back().set_sensitive (
611 !for_selection || _editor.get_selection().tracks.size() == 1);
613 automation_items.push_back (
614 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
615 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
620 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
622 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
624 for (uint8_t chn = 0; chn < 16; chn++) {
625 if (selected_channels & (0x0001 << chn)) {
627 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
628 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
631 menu->set_active (yn);
638 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
640 AutomationType auto_type,
643 using namespace Menu_Helpers;
645 /* count the number of selected channels because we will build a different menu
646 structure if there is more than 1 selected.
649 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
652 for (uint8_t chn = 0; chn < 16; chn++) {
653 if (selected_channels & (0x0001 << chn)) {
662 /* multiple channels - create a submenu, with 1 item per channel */
664 Menu* chn_menu = manage (new Menu);
665 MenuList& chn_items (chn_menu->items());
666 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
668 /* add a couple of items to hide/show all of them */
670 chn_items.push_back (
671 MenuElem (_("Hide all channels"),
672 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
673 false, param_without_channel)));
674 chn_items.push_back (
675 MenuElem (_("Show all channels"),
676 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
677 true, param_without_channel)));
679 for (uint8_t chn = 0; chn < 16; chn++) {
680 if (selected_channels & (0x0001 << chn)) {
682 /* for each selected channel, add a menu item for this controller */
684 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
685 chn_items.push_back (
686 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
687 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
688 fully_qualified_param)));
690 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
691 bool visible = false;
694 if (track->marked_for_display()) {
699 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
700 _channel_command_menu_map[fully_qualified_param] = cmi;
701 cmi->set_active (visible);
705 /* now create an item in the parent menu that has the per-channel list as a submenu */
707 items.push_back (MenuElem (label, *chn_menu));
711 /* just one channel - create a single menu item for this command+channel combination*/
713 for (uint8_t chn = 0; chn < 16; chn++) {
714 if (selected_channels & (0x0001 << chn)) {
716 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
718 CheckMenuElem (label,
719 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
720 fully_qualified_param)));
722 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
723 bool visible = false;
726 if (track->marked_for_display()) {
731 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
732 _channel_command_menu_map[fully_qualified_param] = cmi;
733 cmi->set_active (visible);
735 /* one channel only */
742 /** Add a single menu item for a controller on one channel. */
744 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
746 const std::string& name)
748 using namespace Menu_Helpers;
750 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
751 for (uint8_t chn = 0; chn < 16; chn++) {
752 if (selected_channels & (0x0001 << chn)) {
754 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
755 ctl_items.push_back (
757 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
759 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
760 fully_qualified_param)));
761 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
763 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
764 fully_qualified_param);
766 bool visible = false;
768 if (track->marked_for_display()) {
773 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
774 _controller_menu_map[fully_qualified_param] = cmi;
775 cmi->set_active (visible);
777 /* one channel only */
783 /** Add a submenu with 1 item per channel for a controller on many channels. */
785 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
787 const std::string& name)
789 using namespace Menu_Helpers;
791 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
793 Menu* chn_menu = manage (new Menu);
794 MenuList& chn_items (chn_menu->items());
796 /* add a couple of items to hide/show this controller on all channels */
798 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
799 chn_items.push_back (
800 MenuElem (_("Hide all channels"),
801 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
802 false, param_without_channel)));
803 chn_items.push_back (
804 MenuElem (_("Show all channels"),
805 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
806 true, param_without_channel)));
808 for (uint8_t chn = 0; chn < 16; chn++) {
809 if (selected_channels & (0x0001 << chn)) {
811 /* for each selected channel, add a menu item for this controller */
813 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
814 chn_items.push_back (
815 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
816 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
817 fully_qualified_param)));
819 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
820 fully_qualified_param);
821 bool visible = false;
824 if (track->marked_for_display()) {
829 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
830 _controller_menu_map[fully_qualified_param] = cmi;
831 cmi->set_active (visible);
835 /* add the per-channel menu to the list of controllers, with the name of the controller */
836 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
838 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
841 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
842 MidiTimeAxisView::get_device_mode()
844 using namespace MIDI::Name;
846 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
848 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
851 return device_names->custom_device_mode_by_name(
852 gui_property (X_("midnam-custom-device-mode")));
855 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
856 MidiTimeAxisView::get_device_names()
858 using namespace MIDI::Name;
860 const std::string model = gui_property (X_("midnam-model-name"));
862 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
863 .document_by_model(model);
865 return midnam->master_device_names(model);
867 return boost::shared_ptr<MasterDeviceNames>();
872 MidiTimeAxisView::build_controller_menu ()
874 using namespace Menu_Helpers;
876 if (controller_menu) {
877 /* it exists and has not been invalidated by a channel mode change */
881 controller_menu = new Menu; // explicitly managed by us
882 MenuList& items (controller_menu->items());
884 /* create several "top level" menu items for sets of controllers (16 at a
885 time), and populate each one with a submenu for each controller+channel
886 combination covering the currently selected channels for this track
889 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
891 /* count the number of selected channels because we will build a different menu
892 structure if there is more than 1 selected.
896 for (uint8_t chn = 0; chn < 16; chn++) {
897 if (selected_channels & (0x0001 << chn)) {
904 using namespace MIDI::Name;
905 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
907 if (device_names && !device_names->controls().empty()) {
908 /* Controllers names available in midnam file, generate fancy menu */
909 unsigned n_items = 0;
910 unsigned n_groups = 0;
912 /* TODO: This is not correct, should look up the currently applicable ControlNameList
913 and only build a menu for that one. */
914 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
915 l != device_names->controls().end(); ++l) {
916 boost::shared_ptr<ControlNameList> name_list = l->second;
917 Menu* ctl_menu = NULL;
919 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
920 c != name_list->controls().end();) {
921 const uint16_t ctl = c->second->number();
922 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
923 /* Skip bank select controllers since they're handled specially */
925 /* Create a new submenu */
926 ctl_menu = manage (new Menu);
929 MenuList& ctl_items (ctl_menu->items());
931 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
933 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
938 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
939 /* Submenu has 16 items or we're done, add it to controller menu and reset */
941 MenuElem(string_compose(_("Controllers %1-%2"),
942 (16 * n_groups), (16 * n_groups) + n_items - 1),
951 /* No controllers names, generate generic numeric menu */
952 for (int i = 0; i < 127; i += 16) {
953 Menu* ctl_menu = manage (new Menu);
954 MenuList& ctl_items (ctl_menu->items());
956 for (int ctl = i; ctl < i+16; ++ctl) {
957 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
958 /* Skip bank select controllers since they're handled specially */
963 add_multi_channel_controller_item(
964 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
966 add_single_channel_controller_item(
967 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
971 /* Add submenu for this block of controllers to controller menu */
973 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
980 MidiTimeAxisView::build_note_mode_menu()
982 using namespace Menu_Helpers;
984 Menu* mode_menu = manage (new Menu);
985 MenuList& items = mode_menu->items();
986 mode_menu->set_name ("ArdourContextMenu");
988 RadioMenuItem::Group mode_group;
990 RadioMenuElem (mode_group,_("Sustained"),
991 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
993 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
994 _note_mode_item->set_active(_note_mode == Sustained);
997 RadioMenuElem (mode_group, _("Percussive"),
998 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1000 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1001 _percussion_mode_item->set_active(_note_mode == Percussive);
1007 MidiTimeAxisView::build_color_mode_menu()
1009 using namespace Menu_Helpers;
1011 Menu* mode_menu = manage (new Menu);
1012 MenuList& items = mode_menu->items();
1013 mode_menu->set_name ("ArdourContextMenu");
1015 RadioMenuItem::Group mode_group;
1017 RadioMenuElem (mode_group, _("Meter Colors"),
1018 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1019 MeterColors, false, true, true)));
1020 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1021 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1024 RadioMenuElem (mode_group, _("Channel Colors"),
1025 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1026 ChannelColors, false, true, true)));
1027 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1028 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1031 RadioMenuElem (mode_group, _("Track Color"),
1032 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1033 TrackColor, false, true, true)));
1034 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1035 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1041 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1043 if (apply_to_selection) {
1044 _editor.get_selection().tracks.foreach_midi_time_axis (
1045 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1047 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1049 midi_track()->set_note_mode(mode);
1050 set_gui_property ("note-mode", enum_2_string(_note_mode));
1051 _view->redisplay_track();
1057 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1059 if (apply_to_selection) {
1060 _editor.get_selection().tracks.foreach_midi_time_axis (
1061 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1063 if (_color_mode == mode && !force) {
1067 if (_channel_selector) {
1068 if (mode == ChannelColors) {
1069 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1071 _channel_selector->set_default_channel_color();
1076 set_gui_property ("color-mode", enum_2_string(_color_mode));
1078 _view->redisplay_track();
1084 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1086 if (apply_to_selection) {
1087 _editor.get_selection().tracks.foreach_midi_time_axis (
1088 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1090 if (!_ignore_signals) {
1091 midi_view()->set_note_range(range);
1097 MidiTimeAxisView::update_range()
1099 MidiGhostRegion* mgr;
1101 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1102 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1103 mgr->update_range();
1109 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1111 using namespace MIDI::Name;
1113 if (apply_to_selection) {
1114 _editor.get_selection().tracks.foreach_midi_time_axis (
1115 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1118 // Show existing automation
1119 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1121 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1122 create_automation_child(*i, true);
1125 // Show automation for all controllers named in midnam file
1126 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1127 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1128 device_names && !device_names->controls().empty()) {
1129 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1130 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1131 for (uint32_t chn = 0; chn < 16; ++chn) {
1132 if ((selected_channels & (0x0001 << chn)) == 0) {
1133 // Channel not in use
1137 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1143 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1144 chan_names->control_list_name());
1145 if (!control_names) {
1149 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1150 c != control_names->controls().end();
1152 const uint16_t ctl = c->second->number();
1153 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1154 /* Skip bank select controllers since they're handled specially */
1155 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1156 create_automation_child(param, true);
1163 RouteTimeAxisView::show_all_automation ();
1168 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1170 if (apply_to_selection) {
1171 _editor.get_selection().tracks.foreach_midi_time_axis (
1172 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1175 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1177 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1178 create_automation_child (*i, true);
1182 RouteTimeAxisView::show_existing_automation ();
1186 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1189 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1191 if (param.type() == NullAutomation) {
1195 AutomationTracks::iterator existing = _automation_tracks.find (param);
1197 if (existing != _automation_tracks.end()) {
1199 /* automation track created because we had existing data for
1200 * the processor, but visibility may need to be controlled
1201 * since it will have been set visible by default.
1204 existing->second->set_marked_for_display (show);
1213 boost::shared_ptr<AutomationTimeAxisView> track;
1214 boost::shared_ptr<AutomationControl> control;
1217 switch (param.type()) {
1219 case GainAutomation:
1220 create_gain_automation_child (param, show);
1223 case MuteAutomation:
1224 create_mute_automation_child (param, show);
1227 case PluginAutomation:
1228 /* handled elsewhere */
1231 case MidiCCAutomation:
1232 case MidiPgmChangeAutomation:
1233 case MidiPitchBenderAutomation:
1234 case MidiChannelPressureAutomation:
1235 case MidiSystemExclusiveAutomation:
1236 /* These controllers are region "automation" - they are owned
1237 * by regions (and their MidiModels), not by the track. As a
1238 * result there is no AutomationList/Line for the track, but we create
1239 * a controller for the user to write immediate events, so the editor
1240 * can act as a control surface for the present MIDI controllers.
1242 * TODO: Record manipulation of the controller to regions?
1245 control = _route->automation_control(param, true);
1246 track.reset (new AutomationTimeAxisView (
1249 control ? _route : boost::shared_ptr<Automatable> (),
1256 _route->describe_parameter(param)));
1259 _view->foreach_regionview (
1260 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1263 add_automation_child (param, track, show);
1266 case PanWidthAutomation:
1267 case PanElevationAutomation:
1268 case PanAzimuthAutomation:
1269 ensure_pan_views (show);
1273 error << "MidiTimeAxisView: unknown automation child "
1274 << EventTypeMap::instance().to_symbol(param) << endmsg;
1279 MidiTimeAxisView::route_active_changed ()
1281 RouteUI::route_active_changed ();
1284 if (_route->active()) {
1285 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1286 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1287 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1288 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1290 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1291 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1292 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1293 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1296 if (_route->active()) {
1297 controls_ebox.set_name ("BusControlsBaseUnselected");
1298 time_axis_frame.set_name ("BusControlsBaseUnselected");
1299 controls_base_selected_name = "BusControlsBaseSelected";
1300 controls_base_unselected_name = "BusControlsBaseUnselected";
1302 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1303 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1304 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1305 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1311 MidiTimeAxisView::set_note_selection (uint8_t note)
1313 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1315 _editor.begin_reversible_selection_op(_("Set Note Selection"));
1317 if (_view->num_selected_regionviews() == 0) {
1318 _view->foreach_regionview (
1319 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1322 _view->foreach_selected_regionview (
1323 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1327 _editor.commit_reversible_selection_op();
1331 MidiTimeAxisView::add_note_selection (uint8_t note)
1333 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1335 _editor.begin_reversible_selection_op(_("Add Note Selection"));
1337 if (_view->num_selected_regionviews() == 0) {
1338 _view->foreach_regionview (
1339 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1342 _view->foreach_selected_regionview (
1343 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1347 _editor.commit_reversible_selection_op();
1351 MidiTimeAxisView::extend_note_selection (uint8_t note)
1353 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1355 _editor.begin_reversible_selection_op(_("Extend Note Selection"));
1357 if (_view->num_selected_regionviews() == 0) {
1358 _view->foreach_regionview (
1359 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1362 _view->foreach_selected_regionview (
1363 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1367 _editor.commit_reversible_selection_op();
1371 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1373 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1375 _editor.begin_reversible_selection_op(_("Toggle Note Selection"));
1377 if (_view->num_selected_regionviews() == 0) {
1378 _view->foreach_regionview (
1379 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1382 _view->foreach_selected_regionview (
1383 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1387 _editor.commit_reversible_selection_op();
1391 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1393 _view->foreach_regionview (
1394 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1398 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1400 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1404 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1406 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1410 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1412 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1416 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1418 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1422 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1424 Evoral::Sequence<Evoral::Beats>::Notes selected;
1425 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1427 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1429 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1430 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1431 notes.insert (*sel_it);
1434 if (!notes.empty()) {
1435 selection.push_back (make_pair ((rv)->region()->id(), notes));
1440 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1442 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1446 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1447 bool changed = false;
1451 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1453 for (uint32_t chn = 0; chn < 16; ++chn) {
1454 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1455 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1461 if ((selected_channels & (0x0001 << chn)) == 0) {
1462 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1463 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1465 changed = track->set_marked_for_display (false) || changed;
1467 changed = track->set_marked_for_display (true) || changed;
1474 /* TODO: Bender, Pressure */
1476 /* invalidate the controller menu, so that we rebuild it next time */
1477 _controller_menu_map.clear ();
1478 delete controller_menu;
1479 controller_menu = 0;
1487 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1489 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1494 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1495 if (i != _controller_menu_map.end()) {
1499 i = _channel_command_menu_map.find (param);
1500 if (i != _channel_command_menu_map.end()) {
1507 boost::shared_ptr<MidiRegion>
1508 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1510 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1512 real_editor->begin_reversible_command (Operations::create_region);
1513 playlist()->clear_changes ();
1515 real_editor->snap_to (pos, RoundNearest);
1517 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1520 plist.add (ARDOUR::Properties::start, 0);
1521 plist.add (ARDOUR::Properties::length, length);
1522 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1524 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1526 playlist()->add_region (region, pos);
1527 _session->add_command (new StatefulDiffCommand (playlist()));
1530 real_editor->commit_reversible_command ();
1533 return boost::dynamic_pointer_cast<MidiRegion>(region);
1537 MidiTimeAxisView::ensure_step_editor ()
1539 if (!_step_editor) {
1540 _step_editor = new StepEditor (_editor, midi_track(), *this);
1545 MidiTimeAxisView::start_step_editing ()
1547 ensure_step_editor ();
1548 _step_editor->start_step_editing ();
1552 MidiTimeAxisView::stop_step_editing ()
1555 _step_editor->stop_step_editing ();
1559 /** @return channel (counted from 0) to add an event to, based on the current setting
1560 * of the channel selector.
1563 MidiTimeAxisView::get_channel_for_add () const
1565 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1567 uint8_t channel = 0;
1569 /* pick the highest selected channel, unless all channels are selected,
1570 which is interpreted to mean channel 1 (zero)
1573 for (uint16_t i = 0; i < 16; ++i) {
1574 if (chn_mask & (1<<i)) {
1580 if (chn_cnt == 16) {
1588 MidiTimeAxisView::note_range_changed ()
1590 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1591 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1595 MidiTimeAxisView::contents_height_changed ()
1597 _range_scroomer->queue_resize ();
1601 MidiTimeAxisView::playback_channel_mode_changed ()
1603 switch (midi_track()->get_playback_channel_mode()) {
1605 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1607 case FilterChannels:
1608 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1611 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1617 MidiTimeAxisView::capture_channel_mode_changed ()
1619 switch (midi_track()->get_capture_channel_mode()) {
1621 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1623 case FilterChannels:
1624 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1627 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1633 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
1635 if (!_editor.internal_editing()) {
1636 // Non-internal paste, paste regions like any other route
1637 return RouteTimeAxisView::paste(pos, selection, ctx);
1640 return midi_view()->paste(pos, selection, ctx);