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()->playback_filter().ChannelModeChanged.connect (
247 *this, invalidator (*this),
248 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
250 midi_track()->playback_filter().ChannelMaskChanged.connect (
251 *this, invalidator (*this),
252 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
254 midi_track()->capture_filter().ChannelModeChanged.connect (
255 *this, invalidator (*this),
256 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
258 midi_track()->capture_filter().ChannelMaskChanged.connect (
259 *this, invalidator (*this),
260 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
263 playback_channel_mode_changed ();
264 capture_channel_mode_changed ();
266 if (!_editor.have_idled()) {
267 /* first idle will do what we need */
273 typedef MIDI::Name::MidiPatchManager PatchManager;
275 PatchManager& patch_manager = PatchManager::instance();
277 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
278 m != patch_manager.devices_by_manufacturer().end(); ++m) {
279 Menu* menu = Gtk::manage(new Menu);
280 Menu_Helpers::MenuList& items = menu->items();
282 // Build manufacturer submenu
283 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
284 n != m->second.end(); ++n) {
285 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
287 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
290 items.push_back(elem);
293 // Add manufacturer submenu to selector
294 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
297 if (gui_property (X_("midnam-model-name")).empty()) {
298 set_gui_property (X_("midnam-model-name"), "Generic");
301 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
302 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
304 set_gui_property (X_("midnam-custom-device-mode"),
305 *device_names->custom_device_mode_names().begin());
309 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
310 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
312 _midi_controls_box.set_homogeneous(false);
313 _midi_controls_box.set_border_width (2);
315 _channel_status_box.set_homogeneous (false);
316 _channel_status_box.set_spacing (4);
318 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
319 channel_selector_button->set_name ("route button");
320 ARDOUR_UI::instance()->set_tip (channel_selector_button, _("Click to edit channel settings"));
322 // Insert expanding space labels to get full width justification
323 _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
324 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
325 _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
326 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
327 _channel_status_box.pack_end (*channel_selector_button, false, false);
328 _channel_status_box.show_all ();
330 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
332 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
334 if (!patch_manager.all_models().empty()) {
336 _midnam_model_selector.show ();
337 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
339 _midnam_custom_device_mode_selector.show ();
341 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
344 model_changed(gui_property(X_("midnam-model-name")));
345 custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
347 controls_vbox.pack_start(_midi_controls_box, false, false);
349 const string color_mode = gui_property ("color-mode");
350 if (!color_mode.empty()) {
351 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
352 if (_channel_selector && _color_mode == ChannelColors) {
353 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
357 set_color_mode (_color_mode, true, false);
359 const string note_mode = gui_property ("note-mode");
360 if (!note_mode.empty()) {
361 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
362 if (_percussion_mode_item) {
363 _percussion_mode_item->set_active (_note_mode == Percussive);
367 /* Look for any GUI object state nodes that represent automation children
368 * that should exist, and create the children.
371 const list<string> gui_ids = gui_object_state().all_ids ();
372 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
375 Evoral::Parameter parameter (0, 0, 0);
377 bool const p = AutomationTimeAxisView::parse_state_id (
378 *i, route_id, has_parameter, parameter);
379 if (p && route_id == _route->id () && has_parameter) {
380 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
381 create_automation_child (parameter, string_is_affirmative (visible));
387 MidiTimeAxisView::first_idle ()
394 MidiTimeAxisView::~MidiTimeAxisView ()
396 delete _channel_selector;
398 delete _piano_roll_header;
399 _piano_roll_header = 0;
401 delete _range_scroomer;
404 delete controller_menu;
409 MidiTimeAxisView::check_step_edit ()
411 ensure_step_editor ();
412 _step_editor->check_step_edit ();
416 MidiTimeAxisView::model_changed(const std::string& model)
418 set_gui_property (X_("midnam-model-name"), model);
420 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
421 .custom_device_mode_names_by_model(model);
423 _midnam_model_selector.set_text(model);
424 _midnam_custom_device_mode_selector.clear_items();
426 for (std::list<std::string>::const_iterator i = device_modes.begin();
427 i != device_modes.end(); ++i) {
428 _midnam_custom_device_mode_selector.AddMenuElem(
429 Gtk::Menu_Helpers::MenuElem(
430 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
434 if (!device_modes.empty()) {
435 custom_device_mode_changed(device_modes.front());
438 if (device_modes.size() > 1) {
439 _midnam_custom_device_mode_selector.show();
441 _midnam_custom_device_mode_selector.hide();
444 if (device_modes.size() > 0) {
445 _route->instrument_info().set_external_instrument (model, device_modes.front());
447 _route->instrument_info().set_external_instrument (model, "");
450 // Rebuild controller menu
451 _controller_menu_map.clear ();
452 delete controller_menu;
454 build_automation_action_menu(false);
458 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
460 const std::string model = gui_property (X_("midnam-model-name"));
462 set_gui_property (X_("midnam-custom-device-mode"), mode);
463 _midnam_custom_device_mode_selector.set_text(mode);
464 _route->instrument_info().set_external_instrument (model, mode);
468 MidiTimeAxisView::midi_view()
470 return dynamic_cast<MidiStreamView*>(_view);
474 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
476 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
477 _midi_controls_box.show ();
479 _midi_controls_box.hide();
482 if (h >= KEYBOARD_MIN_HEIGHT) {
483 if (is_track() && _range_scroomer) {
484 _range_scroomer->show();
486 if (is_track() && _piano_roll_header) {
487 _piano_roll_header->show();
490 if (is_track() && _range_scroomer) {
491 _range_scroomer->hide();
493 if (is_track() && _piano_roll_header) {
494 _piano_roll_header->hide();
498 /* We need to do this after changing visibility of our stuff, as it will
499 eventually trigger a call to Editor::reset_controls_layout_width(),
500 which needs to know if we have just shown or hidden a scroomer /
503 RouteTimeAxisView::set_height (h, m);
507 MidiTimeAxisView::append_extra_display_menu_items ()
509 using namespace Menu_Helpers;
511 MenuList& items = display_menu->items();
514 Menu *range_menu = manage(new Menu);
515 MenuList& range_items = range_menu->items();
516 range_menu->set_name ("ArdourContextMenu");
518 range_items.push_back (
519 MenuElem (_("Show Full Range"),
520 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
521 MidiStreamView::FullRange, true)));
523 range_items.push_back (
524 MenuElem (_("Fit Contents"),
525 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
526 MidiStreamView::ContentsRange, true)));
528 items.push_back (MenuElem (_("Note Range"), *range_menu));
529 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
530 items.push_back (MenuElem (_("Channel Selector"),
531 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
533 color_mode_menu = build_color_mode_menu();
534 if (color_mode_menu) {
535 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
538 items.push_back (SeparatorElem ());
542 MidiTimeAxisView::toggle_channel_selector ()
544 if (!_channel_selector) {
545 _channel_selector = new MidiChannelSelectorWindow (midi_track());
547 if (_color_mode == ChannelColors) {
548 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
550 _channel_selector->set_default_channel_color ();
553 _channel_selector->show_all ();
555 _channel_selector->cycle_visibility ();
560 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
562 using namespace Menu_Helpers;
564 /* If we have a controller menu, we need to detach it before
565 RouteTimeAxis::build_automation_action_menu destroys the
566 menu it is attached to. Otherwise GTK destroys
567 controller_menu's gobj, meaning that it can't be reattached
568 below. See bug #3134.
571 if (controller_menu) {
572 detach_menu (*controller_menu);
575 _channel_command_menu_map.clear ();
576 RouteTimeAxisView::build_automation_action_menu (for_selection);
578 MenuList& automation_items = automation_action_menu->items();
580 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
582 if (selected_channels != 0) {
584 automation_items.push_back (SeparatorElem());
586 /* these 2 MIDI "command" types are semantically more like automation
587 than note data, but they are not MIDI controllers. We give them
588 special status in this menu, since they will not show up in the
589 controller list and anyone who actually knows something about MIDI
590 (!) would not expect to find them there.
593 add_channel_command_menu_item (
594 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
595 automation_items.back().set_sensitive (
596 !for_selection || _editor.get_selection().tracks.size() == 1);
597 add_channel_command_menu_item (
598 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
599 automation_items.back().set_sensitive (
600 !for_selection || _editor.get_selection().tracks.size() == 1);
602 /* now all MIDI controllers. Always offer the possibility that we will
603 rebuild the controllers menu since it might need to be updated after
604 a channel mode change or other change. Also detach it first in case
605 it has been used anywhere else.
608 build_controller_menu ();
610 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
611 automation_items.back().set_sensitive (
612 !for_selection || _editor.get_selection().tracks.size() == 1);
614 automation_items.push_back (
615 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
616 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
621 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
623 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
625 for (uint8_t chn = 0; chn < 16; chn++) {
626 if (selected_channels & (0x0001 << chn)) {
628 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
629 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
632 menu->set_active (yn);
639 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
641 AutomationType auto_type,
644 using namespace Menu_Helpers;
646 /* count the number of selected channels because we will build a different menu
647 structure if there is more than 1 selected.
650 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
653 for (uint8_t chn = 0; chn < 16; chn++) {
654 if (selected_channels & (0x0001 << chn)) {
663 /* multiple channels - create a submenu, with 1 item per channel */
665 Menu* chn_menu = manage (new Menu);
666 MenuList& chn_items (chn_menu->items());
667 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
669 /* add a couple of items to hide/show all of them */
671 chn_items.push_back (
672 MenuElem (_("Hide all channels"),
673 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
674 false, param_without_channel)));
675 chn_items.push_back (
676 MenuElem (_("Show all channels"),
677 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
678 true, param_without_channel)));
680 for (uint8_t chn = 0; chn < 16; chn++) {
681 if (selected_channels & (0x0001 << chn)) {
683 /* for each selected channel, add a menu item for this controller */
685 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
686 chn_items.push_back (
687 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
688 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
689 fully_qualified_param)));
691 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
692 bool visible = false;
695 if (track->marked_for_display()) {
700 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
701 _channel_command_menu_map[fully_qualified_param] = cmi;
702 cmi->set_active (visible);
706 /* now create an item in the parent menu that has the per-channel list as a submenu */
708 items.push_back (MenuElem (label, *chn_menu));
712 /* just one channel - create a single menu item for this command+channel combination*/
714 for (uint8_t chn = 0; chn < 16; chn++) {
715 if (selected_channels & (0x0001 << chn)) {
717 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
719 CheckMenuElem (label,
720 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
721 fully_qualified_param)));
723 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
724 bool visible = false;
727 if (track->marked_for_display()) {
732 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
733 _channel_command_menu_map[fully_qualified_param] = cmi;
734 cmi->set_active (visible);
736 /* one channel only */
743 /** Add a single menu item for a controller on one channel. */
745 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
747 const std::string& name)
749 using namespace Menu_Helpers;
751 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
752 for (uint8_t chn = 0; chn < 16; chn++) {
753 if (selected_channels & (0x0001 << chn)) {
755 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
756 ctl_items.push_back (
758 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
760 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
761 fully_qualified_param)));
762 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
764 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
765 fully_qualified_param);
767 bool visible = false;
769 if (track->marked_for_display()) {
774 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
775 _controller_menu_map[fully_qualified_param] = cmi;
776 cmi->set_active (visible);
778 /* one channel only */
784 /** Add a submenu with 1 item per channel for a controller on many channels. */
786 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
788 const std::string& name)
790 using namespace Menu_Helpers;
792 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
794 Menu* chn_menu = manage (new Menu);
795 MenuList& chn_items (chn_menu->items());
797 /* add a couple of items to hide/show this controller on all channels */
799 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
800 chn_items.push_back (
801 MenuElem (_("Hide all channels"),
802 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
803 false, param_without_channel)));
804 chn_items.push_back (
805 MenuElem (_("Show all channels"),
806 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
807 true, param_without_channel)));
809 for (uint8_t chn = 0; chn < 16; chn++) {
810 if (selected_channels & (0x0001 << chn)) {
812 /* for each selected channel, add a menu item for this controller */
814 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
815 chn_items.push_back (
816 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
817 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
818 fully_qualified_param)));
820 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
821 fully_qualified_param);
822 bool visible = false;
825 if (track->marked_for_display()) {
830 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
831 _controller_menu_map[fully_qualified_param] = cmi;
832 cmi->set_active (visible);
836 /* add the per-channel menu to the list of controllers, with the name of the controller */
837 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
839 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
842 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
843 MidiTimeAxisView::get_device_mode()
845 using namespace MIDI::Name;
847 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
849 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
852 return device_names->custom_device_mode_by_name(
853 gui_property (X_("midnam-custom-device-mode")));
856 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
857 MidiTimeAxisView::get_device_names()
859 using namespace MIDI::Name;
861 const std::string model = gui_property (X_("midnam-model-name"));
863 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
864 .document_by_model(model);
866 return midnam->master_device_names(model);
868 return boost::shared_ptr<MasterDeviceNames>();
873 MidiTimeAxisView::build_controller_menu ()
875 using namespace Menu_Helpers;
877 if (controller_menu) {
878 /* it exists and has not been invalidated by a channel mode change */
882 controller_menu = new Menu; // explicitly managed by us
883 MenuList& items (controller_menu->items());
885 /* create several "top level" menu items for sets of controllers (16 at a
886 time), and populate each one with a submenu for each controller+channel
887 combination covering the currently selected channels for this track
890 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
892 /* count the number of selected channels because we will build a different menu
893 structure if there is more than 1 selected.
897 for (uint8_t chn = 0; chn < 16; chn++) {
898 if (selected_channels & (0x0001 << chn)) {
905 using namespace MIDI::Name;
906 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
908 if (device_names && !device_names->controls().empty()) {
909 /* Controllers names available in midnam file, generate fancy menu */
910 unsigned n_items = 0;
911 unsigned n_groups = 0;
913 /* TODO: This is not correct, should look up the currently applicable ControlNameList
914 and only build a menu for that one. */
915 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
916 l != device_names->controls().end(); ++l) {
917 boost::shared_ptr<ControlNameList> name_list = l->second;
918 Menu* ctl_menu = NULL;
920 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
921 c != name_list->controls().end();) {
922 const uint16_t ctl = c->second->number();
923 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
924 /* Skip bank select controllers since they're handled specially */
926 /* Create a new submenu */
927 ctl_menu = manage (new Menu);
930 MenuList& ctl_items (ctl_menu->items());
932 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
934 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
939 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
940 /* Submenu has 16 items or we're done, add it to controller menu and reset */
942 MenuElem(string_compose(_("Controllers %1-%2"),
943 (16 * n_groups), (16 * n_groups) + n_items - 1),
952 /* No controllers names, generate generic numeric menu */
953 for (int i = 0; i < 127; i += 16) {
954 Menu* ctl_menu = manage (new Menu);
955 MenuList& ctl_items (ctl_menu->items());
957 for (int ctl = i; ctl < i+16; ++ctl) {
958 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
959 /* Skip bank select controllers since they're handled specially */
964 add_multi_channel_controller_item(
965 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
967 add_single_channel_controller_item(
968 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
972 /* Add submenu for this block of controllers to controller menu */
974 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
981 MidiTimeAxisView::build_note_mode_menu()
983 using namespace Menu_Helpers;
985 Menu* mode_menu = manage (new Menu);
986 MenuList& items = mode_menu->items();
987 mode_menu->set_name ("ArdourContextMenu");
989 RadioMenuItem::Group mode_group;
991 RadioMenuElem (mode_group,_("Sustained"),
992 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
994 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
995 _note_mode_item->set_active(_note_mode == Sustained);
998 RadioMenuElem (mode_group, _("Percussive"),
999 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1000 Percussive, true)));
1001 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1002 _percussion_mode_item->set_active(_note_mode == Percussive);
1008 MidiTimeAxisView::build_color_mode_menu()
1010 using namespace Menu_Helpers;
1012 Menu* mode_menu = manage (new Menu);
1013 MenuList& items = mode_menu->items();
1014 mode_menu->set_name ("ArdourContextMenu");
1016 RadioMenuItem::Group mode_group;
1018 RadioMenuElem (mode_group, _("Meter Colors"),
1019 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1020 MeterColors, false, true, true)));
1021 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1022 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1025 RadioMenuElem (mode_group, _("Channel Colors"),
1026 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1027 ChannelColors, false, true, true)));
1028 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1029 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1032 RadioMenuElem (mode_group, _("Track Color"),
1033 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1034 TrackColor, false, true, true)));
1035 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1036 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1042 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1044 if (apply_to_selection) {
1045 _editor.get_selection().tracks.foreach_midi_time_axis (
1046 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1048 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1050 midi_track()->set_note_mode(mode);
1051 set_gui_property ("note-mode", enum_2_string(_note_mode));
1052 _view->redisplay_track();
1058 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1060 if (apply_to_selection) {
1061 _editor.get_selection().tracks.foreach_midi_time_axis (
1062 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1064 if (_color_mode == mode && !force) {
1068 if (_channel_selector) {
1069 if (mode == ChannelColors) {
1070 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1072 _channel_selector->set_default_channel_color();
1077 set_gui_property ("color-mode", enum_2_string(_color_mode));
1079 _view->redisplay_track();
1085 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1087 if (apply_to_selection) {
1088 _editor.get_selection().tracks.foreach_midi_time_axis (
1089 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1091 if (!_ignore_signals) {
1092 midi_view()->set_note_range(range);
1098 MidiTimeAxisView::update_range()
1100 MidiGhostRegion* mgr;
1102 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1103 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1104 mgr->update_range();
1110 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1112 using namespace MIDI::Name;
1114 if (apply_to_selection) {
1115 _editor.get_selection().tracks.foreach_midi_time_axis (
1116 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1119 // Show existing automation
1120 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1122 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1123 create_automation_child(*i, true);
1126 // Show automation for all controllers named in midnam file
1127 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1128 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1129 device_names && !device_names->controls().empty()) {
1130 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1131 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1132 for (uint32_t chn = 0; chn < 16; ++chn) {
1133 if ((selected_channels & (0x0001 << chn)) == 0) {
1134 // Channel not in use
1138 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1144 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1145 chan_names->control_list_name());
1146 if (!control_names) {
1150 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1151 c != control_names->controls().end();
1153 const uint16_t ctl = c->second->number();
1154 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1155 /* Skip bank select controllers since they're handled specially */
1156 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1157 create_automation_child(param, true);
1164 RouteTimeAxisView::show_all_automation ();
1169 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1171 if (apply_to_selection) {
1172 _editor.get_selection().tracks.foreach_midi_time_axis (
1173 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1176 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1178 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1179 create_automation_child (*i, true);
1183 RouteTimeAxisView::show_existing_automation ();
1187 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1190 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1192 if (param.type() == NullAutomation) {
1196 AutomationTracks::iterator existing = _automation_tracks.find (param);
1198 if (existing != _automation_tracks.end()) {
1200 /* automation track created because we had existing data for
1201 * the processor, but visibility may need to be controlled
1202 * since it will have been set visible by default.
1205 existing->second->set_marked_for_display (show);
1214 boost::shared_ptr<AutomationTimeAxisView> track;
1215 boost::shared_ptr<AutomationControl> control;
1218 switch (param.type()) {
1220 case GainAutomation:
1221 create_gain_automation_child (param, show);
1224 case MuteAutomation:
1225 create_mute_automation_child (param, show);
1228 case PluginAutomation:
1229 /* handled elsewhere */
1232 case MidiCCAutomation:
1233 case MidiPgmChangeAutomation:
1234 case MidiPitchBenderAutomation:
1235 case MidiChannelPressureAutomation:
1236 case MidiSystemExclusiveAutomation:
1237 /* These controllers are region "automation" - they are owned
1238 * by regions (and their MidiModels), not by the track. As a
1239 * result there is no AutomationList/Line for the track, but we create
1240 * a controller for the user to write immediate events, so the editor
1241 * can act as a control surface for the present MIDI controllers.
1243 * TODO: Record manipulation of the controller to regions?
1246 control = _route->automation_control(param, true);
1247 track.reset (new AutomationTimeAxisView (
1250 control ? _route : boost::shared_ptr<Automatable> (),
1257 _route->describe_parameter(param)));
1260 _view->foreach_regionview (
1261 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1264 add_automation_child (param, track, show);
1267 case PanWidthAutomation:
1268 case PanElevationAutomation:
1269 case PanAzimuthAutomation:
1270 ensure_pan_views (show);
1274 error << "MidiTimeAxisView: unknown automation child "
1275 << EventTypeMap::instance().to_symbol(param) << endmsg;
1280 MidiTimeAxisView::route_active_changed ()
1282 RouteUI::route_active_changed ();
1285 if (_route->active()) {
1286 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1287 time_axis_frame.set_name ("MidiTrackControlsBaseUnselected");
1288 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1289 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1291 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1292 time_axis_frame.set_name ("MidiTrackControlsBaseInactiveUnselected");
1293 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1294 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1297 if (_route->active()) {
1298 controls_ebox.set_name ("BusControlsBaseUnselected");
1299 time_axis_frame.set_name ("BusControlsBaseUnselected");
1300 controls_base_selected_name = "BusControlsBaseSelected";
1301 controls_base_unselected_name = "BusControlsBaseUnselected";
1303 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1304 time_axis_frame.set_name ("BusControlsBaseInactiveUnselected");
1305 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1306 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1312 MidiTimeAxisView::set_note_selection (uint8_t note)
1314 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1316 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1318 if (_view->num_selected_regionviews() == 0) {
1319 _view->foreach_regionview (
1320 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1323 _view->foreach_selected_regionview (
1324 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1328 _editor.commit_reversible_selection_op();
1332 MidiTimeAxisView::add_note_selection (uint8_t note)
1334 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1336 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1338 if (_view->num_selected_regionviews() == 0) {
1339 _view->foreach_regionview (
1340 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1343 _view->foreach_selected_regionview (
1344 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1348 _editor.commit_reversible_selection_op();
1352 MidiTimeAxisView::extend_note_selection (uint8_t note)
1354 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1356 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1358 if (_view->num_selected_regionviews() == 0) {
1359 _view->foreach_regionview (
1360 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1363 _view->foreach_selected_regionview (
1364 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1368 _editor.commit_reversible_selection_op();
1372 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1374 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1376 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1378 if (_view->num_selected_regionviews() == 0) {
1379 _view->foreach_regionview (
1380 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1383 _view->foreach_selected_regionview (
1384 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1388 _editor.commit_reversible_selection_op();
1392 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1394 _view->foreach_regionview (
1395 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1399 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1401 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1405 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1407 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1411 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1413 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1417 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1419 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1423 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1425 Evoral::Sequence<Evoral::Beats>::Notes selected;
1426 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1428 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1430 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1431 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1432 notes.insert (*sel_it);
1435 if (!notes.empty()) {
1436 selection.push_back (make_pair ((rv)->region()->id(), notes));
1441 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1443 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1447 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1448 bool changed = false;
1452 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1454 for (uint32_t chn = 0; chn < 16; ++chn) {
1455 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1456 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1462 if ((selected_channels & (0x0001 << chn)) == 0) {
1463 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1464 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1466 changed = track->set_marked_for_display (false) || changed;
1468 changed = track->set_marked_for_display (true) || changed;
1475 /* TODO: Bender, Pressure */
1477 /* invalidate the controller menu, so that we rebuild it next time */
1478 _controller_menu_map.clear ();
1479 delete controller_menu;
1480 controller_menu = 0;
1488 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1490 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1495 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1496 if (i != _controller_menu_map.end()) {
1500 i = _channel_command_menu_map.find (param);
1501 if (i != _channel_command_menu_map.end()) {
1508 boost::shared_ptr<MidiRegion>
1509 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1511 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1513 real_editor->begin_reversible_command (Operations::create_region);
1514 playlist()->clear_changes ();
1516 real_editor->snap_to (pos, RoundNearest);
1518 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1521 plist.add (ARDOUR::Properties::start, 0);
1522 plist.add (ARDOUR::Properties::length, length);
1523 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1525 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1527 playlist()->add_region (region, pos);
1528 _session->add_command (new StatefulDiffCommand (playlist()));
1531 real_editor->commit_reversible_command ();
1534 return boost::dynamic_pointer_cast<MidiRegion>(region);
1538 MidiTimeAxisView::ensure_step_editor ()
1540 if (!_step_editor) {
1541 _step_editor = new StepEditor (_editor, midi_track(), *this);
1546 MidiTimeAxisView::start_step_editing ()
1548 ensure_step_editor ();
1549 _step_editor->start_step_editing ();
1553 MidiTimeAxisView::stop_step_editing ()
1556 _step_editor->stop_step_editing ();
1560 /** @return channel (counted from 0) to add an event to, based on the current setting
1561 * of the channel selector.
1564 MidiTimeAxisView::get_channel_for_add () const
1566 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1568 uint8_t channel = 0;
1570 /* pick the highest selected channel, unless all channels are selected,
1571 which is interpreted to mean channel 1 (zero)
1574 for (uint16_t i = 0; i < 16; ++i) {
1575 if (chn_mask & (1<<i)) {
1581 if (chn_cnt == 16) {
1589 MidiTimeAxisView::note_range_changed ()
1591 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1592 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1596 MidiTimeAxisView::contents_height_changed ()
1598 _range_scroomer->queue_resize ();
1602 MidiTimeAxisView::playback_channel_mode_changed ()
1604 switch (midi_track()->get_playback_channel_mode()) {
1606 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1608 case FilterChannels:
1609 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1612 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1618 MidiTimeAxisView::capture_channel_mode_changed ()
1620 switch (midi_track()->get_capture_channel_mode()) {
1622 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1624 case FilterChannels:
1625 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1628 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1634 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
1636 if (!_editor.internal_editing()) {
1637 // Non-internal paste, paste regions like any other route
1638 return RouteTimeAxisView::paste(pos, selection, ctx);
1641 return midi_view()->paste(pos, selection, ctx);