2 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
3 * Copyright (C) 2008-2012 Hans Baier <hansfbaier@googlemail.com>
4 * Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
7 * Copyright (C) 2013-2016 Tim Mayberry <mojofunk@gmail.com>
8 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2014-2017 Ben Loftis <ben@harrisonconsoles.com>
10 * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include <sigc++/bind.h>
36 #include <gtkmm/separator.h>
37 #include <gtkmm/stock.h>
39 #include "pbd/error.h"
41 #include "pbd/stl_delete.h"
42 #include "pbd/whitespace.h"
43 #include "pbd/basename.h"
44 #include "pbd/enumwriter.h"
45 #include "pbd/memento_command.h"
46 #include "pbd/stateful_diff_command.h"
48 #include "gtkmm2ext/gtk_ui.h"
49 #include "gtkmm2ext/utils.h"
51 #include "widgets/tooltips.h"
53 #include "ardour/event_type_map.h"
54 #include "ardour/midi_patch_manager.h"
55 #include "ardour/midi_playlist.h"
56 #include "ardour/midi_region.h"
57 #include "ardour/midi_source.h"
58 #include "ardour/midi_track.h"
59 #include "ardour/operations.h"
60 #include "ardour/pannable.h"
61 #include "ardour/panner.h"
62 #include "ardour/panner_shell.h"
63 #include "ardour/playlist.h"
64 #include "ardour/plugin_insert.h"
65 #include "ardour/profile.h"
66 #include "ardour/region.h"
67 #include "ardour/region_factory.h"
68 #include "ardour/route.h"
69 #include "ardour/session.h"
70 #include "ardour/session_object.h"
71 #include "ardour/source.h"
72 #include "ardour/track.h"
73 #include "ardour/types.h"
75 #include "automation_line.h"
76 #include "automation_time_axis.h"
79 #include "ghostregion.h"
80 #include "gui_thread.h"
82 #include "midi_channel_selector.h"
83 #include "midi_scroomer.h"
84 #include "midi_streamview.h"
85 #include "midi_region_view.h"
86 #include "midi_time_axis.h"
87 #include "patch_change_dialog.h"
88 #include "patch_change_widget.h"
89 #include "piano_roll_header.h"
90 #include "playlist_selector.h"
91 #include "plugin_selector.h"
92 #include "plugin_ui.h"
93 #include "point_selection.h"
94 #include "region_view.h"
95 #include "rgb_macros.h"
96 #include "selection.h"
97 #include "step_editor.h"
99 #include "note_base.h"
101 #include "ardour/midi_track.h"
103 #include "pbd/i18n.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
112 // Minimum height at which a control is displayed
113 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
114 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
116 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
117 : SessionHandlePtr (sess)
118 , RouteTimeAxisView (ed, sess, canvas)
119 , _ignore_signals(false)
121 , _piano_roll_header(0)
122 , _note_mode(Sustained)
124 , _percussion_mode_item(0)
125 , _color_mode(MeterColors)
126 , _meter_color_mode_item(0)
127 , _channel_color_mode_item(0)
128 , _track_color_mode_item(0)
129 , _channel_selector (0)
130 , _step_edit_item (0)
131 , controller_menu (0)
132 , poly_pressure_menu (0)
135 _midnam_model_selector.disable_scrolling();
136 _midnam_custom_device_mode_selector.disable_scrolling();
140 MidiTimeAxisView::set_note_highlight (uint8_t note) {
141 _piano_roll_header->set_note_highlight (note);
145 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
149 _view = new MidiStreamView (*this);
152 _piano_roll_header = new PianoRollHeader(*midi_view());
153 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
154 _range_scroomer->DoubleClicked.connect (
155 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
156 MidiStreamView::ContentsRange, false));
159 /* This next call will result in our height being set up, so it must come after
160 the creation of the piano roll / range scroomer as their visibility is set up
163 RouteTimeAxisView::set_route (rt);
165 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
167 subplugin_menu.set_name ("ArdourContextMenu");
169 _note_range_changed_connection.disconnect();
171 if (!gui_property ("note-range-min").empty ()) {
172 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
173 atoi (gui_property ("note-range-max").c_str()),
177 _view->ContentsHeightChanged.connect (
178 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
180 ignore_toggle = false;
182 if (is_midi_track()) {
183 _note_mode = midi_track()->note_mode();
186 /* if set_state above didn't create a gain automation child, we need to make one */
187 if (automation_child (GainAutomation) == 0) {
188 create_automation_child (GainAutomation, false);
191 /* if set_state above didn't create a mute automation child, we need to make one */
192 if (automation_child (MuteAutomation) == 0) {
193 create_automation_child (MuteAutomation, false);
196 if (_route->panner_shell()) {
197 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
200 /* map current state of the route */
201 ensure_pan_views (false);
202 update_control_names();
203 processors_changed (RouteProcessorChange ());
206 _piano_roll_header->SetNoteSelection.connect (
207 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
208 _piano_roll_header->AddNoteSelection.connect (
209 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
210 _piano_roll_header->ExtendNoteSelection.connect (
211 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
212 _piano_roll_header->ToggleNoteSelection.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
215 /* Put the scroomer and the keyboard in a VBox with a padding
216 label so that they can be reduced in height for stacked-view
220 HSeparator* separator = manage (new HSeparator());
221 separator->set_name("TrackSeparator");
222 separator->set_size_request(-1, 1);
225 VBox* v = manage (new VBox);
226 HBox* h = manage (new HBox);
227 h->pack_end (*_piano_roll_header);
228 h->pack_end (*_range_scroomer);
229 v->pack_start (*separator, false, false);
230 v->pack_start (*h, true, true);
233 top_hbox.remove(scroomer_placeholder);
234 time_axis_hbox.pack_end(*v, false, false, 0);
235 midi_scroomer_size_group->add_widget (*v);
237 /* callback from StreamView scroomer drags, as well as
238 * automatic changes of note-range (e.g. at rec-stop).
239 * This callback is used to save the note-range-min/max
240 * GUI Object property
242 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
243 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
245 /* ask for notifications of any new RegionViews */
246 _view->RegionViewAdded.connect (
247 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
249 if (!_editor.have_idled()) {
250 /* first idle will do what we need */
256 if (gui_property (X_("midnam-model-name")).empty()) {
257 set_gui_property (X_("midnam-model-name"), "Generic");
260 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
261 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
263 set_gui_property (X_("midnam-custom-device-mode"),
264 *device_names->custom_device_mode_names().begin());
268 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
269 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
271 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
272 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
274 _midi_controls_box.set_homogeneous(false);
275 _midi_controls_box.set_border_width (2);
277 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
278 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
281 setup_midnam_patches ();
282 update_patch_selector ();
284 model_changed (gui_property(X_("midnam-model-name")));
285 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
287 controls_vbox.pack_start(_midi_controls_box, false, false);
289 const string color_mode = gui_property ("color-mode");
290 if (!color_mode.empty()) {
291 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
292 if (_channel_selector && _color_mode == ChannelColors) {
293 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
297 set_color_mode (_color_mode, true, false);
299 const string note_mode = gui_property ("note-mode");
300 if (!note_mode.empty()) {
301 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
302 if (_percussion_mode_item) {
303 _percussion_mode_item->set_active (_note_mode == Percussive);
307 /* Look for any GUI object state nodes that represent automation children
308 * that should exist, and create the children.
311 const list<string> gui_ids = gui_object_state().all_ids ();
312 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
315 Evoral::Parameter parameter (0, 0, 0);
317 bool const p = AutomationTimeAxisView::parse_state_id (
318 *i, route_id, has_parameter, parameter);
319 if (p && route_id == _route->id () && has_parameter) {
320 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
321 create_automation_child (parameter, string_to<bool> (visible));
327 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
329 RouteTimeAxisView::processors_changed (c);
330 update_patch_selector ();
334 MidiTimeAxisView::first_idle ()
341 MidiTimeAxisView::~MidiTimeAxisView ()
343 delete _channel_selector;
345 delete _piano_roll_header;
346 _piano_roll_header = 0;
348 delete _range_scroomer;
351 delete controller_menu;
356 MidiTimeAxisView::check_step_edit ()
358 ensure_step_editor ();
359 _step_editor->check_step_edit ();
363 MidiTimeAxisView::setup_midnam_patches ()
365 typedef MIDI::Name::MidiPatchManager PatchManager;
366 PatchManager& patch_manager = PatchManager::instance();
368 _midnam_model_selector.clear_items ();
371 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
372 if (pi && pi->plugin ()->has_midnam ()) {
373 std::string model_name = pi->plugin ()->midnam_model ();
375 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
376 _("Plugin Provided"),
377 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
380 _midnam_model_selector.AddMenuElem(elem);
384 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
385 m != patch_manager.devices_by_manufacturer().end(); ++m) {
386 Menu* menu = Gtk::manage(new Menu);
387 Menu_Helpers::MenuList& items = menu->items();
389 // Build manufacturer submenu
390 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
391 n != m->second.end(); ++n) {
393 if (patch_manager.is_custom_model (n->first)) {
397 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
399 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
402 items.push_back(elem);
404 if (items.empty ()) {
409 // Add manufacturer submenu to selector
410 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
413 if (!get_device_names()) {
414 model_changed ("Generic");
419 MidiTimeAxisView::update_patch_selector ()
421 typedef MIDI::Name::MidiPatchManager PatchManager;
422 PatchManager& patch_manager = PatchManager::instance();
425 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
426 if (pi && pi->plugin ()->has_midnam ()) {
427 std::string model_name = pi->plugin ()->midnam_model ();
428 if (gui_property (X_("midnam-model-name")) != model_name) {
429 /* ensure that "Plugin Provided" is prefixed at the top of the list */
430 if (_midnam_model_selector.items().empty () || _midnam_model_selector.items().begin()->get_label() != _("Plugin Provided")) {
431 setup_midnam_patches ();
433 model_changed (model_name);
438 if (patch_manager.all_models().empty()) {
439 _midnam_model_selector.hide ();
440 _midnam_custom_device_mode_selector.hide ();
442 _midnam_model_selector.show ();
443 if (_midnam_custom_device_mode_selector.items().size() > 1) {
444 _midnam_custom_device_mode_selector.show ();
451 MidiTimeAxisView::model_changed(const std::string& model)
453 set_gui_property (X_("midnam-model-name"), model);
455 typedef MIDI::Name::MidiPatchManager PatchManager;
456 PatchManager& patch_manager = PatchManager::instance();
458 const std::list<std::string> device_modes = patch_manager.custom_device_mode_names_by_model(model);
460 if (patch_manager.is_custom_model (model)) {
461 _midnam_model_selector.set_text(_("Plugin Provided"));
463 _midnam_model_selector.set_text(model);
465 _midnam_custom_device_mode_selector.clear_items();
467 for (std::list<std::string>::const_iterator i = device_modes.begin();
468 i != device_modes.end(); ++i) {
469 _midnam_custom_device_mode_selector.AddMenuElem(
470 Gtk::Menu_Helpers::MenuElem(
471 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
475 if (!device_modes.empty()) {
476 custom_device_mode_changed(device_modes.front());
479 if (device_modes.size() > 1) {
480 _midnam_custom_device_mode_selector.show();
482 _midnam_custom_device_mode_selector.hide();
485 // now this is a real bad hack
486 if (device_modes.size() > 0) {
487 _route->instrument_info().set_external_instrument (model, device_modes.front());
489 _route->instrument_info().set_external_instrument (model, "");
492 // Rebuild controller menu
493 _controller_menu_map.clear ();
494 delete controller_menu;
496 build_automation_action_menu(false);
498 if (patch_change_dialog ()) {
499 patch_change_dialog ()->refresh ();
504 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
506 const std::string model = gui_property (X_("midnam-model-name"));
508 set_gui_property (X_("midnam-custom-device-mode"), mode);
509 _midnam_custom_device_mode_selector.set_text(mode);
510 _route->instrument_info().set_external_instrument (model, mode);
514 MidiTimeAxisView::midi_view()
516 return dynamic_cast<MidiStreamView*>(_view);
520 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
522 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
523 _midi_controls_box.show ();
525 _midi_controls_box.hide();
528 if (h >= KEYBOARD_MIN_HEIGHT) {
529 if (is_track() && _range_scroomer) {
530 _range_scroomer->show();
532 if (is_track() && _piano_roll_header) {
533 _piano_roll_header->show();
536 if (is_track() && _range_scroomer) {
537 _range_scroomer->hide();
539 if (is_track() && _piano_roll_header) {
540 _piano_roll_header->hide();
544 /* We need to do this after changing visibility of our stuff, as it will
545 eventually trigger a call to Editor::reset_controls_layout_width(),
546 which needs to know if we have just shown or hidden a scroomer /
549 RouteTimeAxisView::set_height (h, m);
553 MidiTimeAxisView::append_extra_display_menu_items ()
555 using namespace Menu_Helpers;
557 MenuList& items = display_menu->items();
560 Menu *range_menu = manage(new Menu);
561 MenuList& range_items = range_menu->items();
562 range_menu->set_name ("ArdourContextMenu");
564 range_items.push_back (
565 MenuElem (_("Show Full Range"),
566 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
567 MidiStreamView::FullRange, true)));
569 range_items.push_back (
570 MenuElem (_("Fit Contents"),
571 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
572 MidiStreamView::ContentsRange, true)));
574 items.push_back (MenuElem (_("Note Range"), *range_menu));
575 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
576 items.push_back (MenuElem (_("Channel Selector..."),
577 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
579 items.push_back (MenuElem (_("Patch Selector..."),
580 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
582 items.push_back (MenuElem (_("Color Mode"), *build_color_mode_menu ()));
584 items.push_back (SeparatorElem ());
588 MidiTimeAxisView::toggle_channel_selector ()
590 if (!_channel_selector) {
591 _channel_selector = new MidiChannelSelectorWindow (midi_track());
593 if (_color_mode == ChannelColors) {
594 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
596 _channel_selector->set_default_channel_color ();
599 _channel_selector->show_all ();
601 _channel_selector->cycle_visibility ();
606 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
608 using namespace Menu_Helpers;
610 /* If we have a controller menu, we need to detach it before
611 RouteTimeAxis::build_automation_action_menu destroys the
612 menu it is attached to. Otherwise GTK destroys
613 controller_menu's gobj, meaning that it can't be reattached
614 below. See bug #3134.
617 if (controller_menu) {
618 detach_menu (*controller_menu);
621 _channel_command_menu_map.clear ();
622 RouteTimeAxisView::build_automation_action_menu (for_selection);
624 MenuList& automation_items = automation_action_menu->items();
626 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
628 if (selected_channels != 0) {
630 automation_items.push_back (SeparatorElem());
632 /* these 2 MIDI "command" types are semantically more like automation
633 than note data, but they are not MIDI controllers. We give them
634 special status in this menu, since they will not show up in the
635 controller list and anyone who actually knows something about MIDI
636 (!) would not expect to find them there.
639 add_channel_command_menu_item (
640 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
641 automation_items.back().set_sensitive (
642 !for_selection || _editor.get_selection().tracks.size() == 1);
643 add_channel_command_menu_item (
644 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
645 automation_items.back().set_sensitive (
646 !for_selection || _editor.get_selection().tracks.size() == 1);
648 /* now all MIDI controllers. Always offer the possibility that we will
649 rebuild the controllers menu since it might need to be updated after
650 a channel mode change or other change. Also detach it first in case
651 it has been used anywhere else.
654 build_controller_menu ();
656 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
658 if (!poly_pressure_menu) {
659 poly_pressure_menu = new Gtk::Menu;
662 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
664 automation_items.back().set_sensitive (
665 !for_selection || _editor.get_selection().tracks.size() == 1);
667 automation_items.push_back (
668 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
669 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
674 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
676 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
678 for (uint8_t chn = 0; chn < 16; chn++) {
679 if (selected_channels & (0x0001 << chn)) {
681 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
682 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
685 menu->set_active (yn);
692 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
694 AutomationType auto_type,
697 using namespace Menu_Helpers;
699 /* count the number of selected channels because we will build a different menu
700 structure if there is more than 1 selected.
703 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
706 for (uint8_t chn = 0; chn < 16; chn++) {
707 if (selected_channels & (0x0001 << chn)) {
716 /* multiple channels - create a submenu, with 1 item per channel */
718 Menu* chn_menu = manage (new Menu);
719 MenuList& chn_items (chn_menu->items());
720 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
722 /* add a couple of items to hide/show all of them */
724 chn_items.push_back (
725 MenuElem (_("Hide all channels"),
726 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
727 false, param_without_channel)));
728 chn_items.push_back (
729 MenuElem (_("Show all channels"),
730 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
731 true, param_without_channel)));
733 for (uint8_t chn = 0; chn < 16; chn++) {
734 if (selected_channels & (0x0001 << chn)) {
736 /* for each selected channel, add a menu item for this controller */
738 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
739 chn_items.push_back (
740 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
741 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
742 fully_qualified_param)));
744 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
745 bool visible = false;
748 if (track->marked_for_display()) {
753 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
754 _channel_command_menu_map[fully_qualified_param] = cmi;
755 cmi->set_active (visible);
759 /* now create an item in the parent menu that has the per-channel list as a submenu */
761 items.push_back (MenuElem (label, *chn_menu));
765 /* just one channel - create a single menu item for this command+channel combination*/
767 for (uint8_t chn = 0; chn < 16; chn++) {
768 if (selected_channels & (0x0001 << chn)) {
770 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
772 CheckMenuElem (label,
773 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
774 fully_qualified_param)));
776 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
777 bool visible = false;
780 if (track->marked_for_display()) {
785 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
786 _channel_command_menu_map[fully_qualified_param] = cmi;
787 cmi->set_active (visible);
789 /* one channel only */
796 /** Add a single menu item for a controller on one channel. */
798 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
800 const std::string& name)
802 using namespace Menu_Helpers;
804 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
805 for (uint8_t chn = 0; chn < 16; chn++) {
806 if (selected_channels & (0x0001 << chn)) {
808 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
809 ctl_items.push_back (
811 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
813 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
814 fully_qualified_param)));
815 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
817 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
818 fully_qualified_param);
820 bool visible = false;
822 if (track->marked_for_display()) {
827 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
828 _controller_menu_map[fully_qualified_param] = cmi;
829 cmi->set_active (visible);
831 /* one channel only */
837 /** Add a submenu with 1 item per channel for a controller on many channels. */
839 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
841 const std::string& name)
843 using namespace Menu_Helpers;
845 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
847 Menu* chn_menu = manage (new Menu);
848 MenuList& chn_items (chn_menu->items());
850 /* add a couple of items to hide/show this controller on all channels */
852 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
853 chn_items.push_back (
854 MenuElem (_("Hide all channels"),
855 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
856 false, param_without_channel)));
857 chn_items.push_back (
858 MenuElem (_("Show all channels"),
859 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
860 true, param_without_channel)));
862 for (uint8_t chn = 0; chn < 16; chn++) {
863 if (selected_channels & (0x0001 << chn)) {
865 /* for each selected channel, add a menu item for this controller */
867 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
868 chn_items.push_back (
869 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
870 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
871 fully_qualified_param)));
873 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
874 fully_qualified_param);
875 bool visible = false;
878 if (track->marked_for_display()) {
883 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
884 _controller_menu_map[fully_qualified_param] = cmi;
885 cmi->set_active (visible);
889 /* add the per-channel menu to the list of controllers, with the name of the controller */
890 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
892 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
895 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
896 MidiTimeAxisView::get_device_mode()
898 using namespace MIDI::Name;
900 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
902 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
905 return device_names->custom_device_mode_by_name(
906 gui_property (X_("midnam-custom-device-mode")));
909 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
910 MidiTimeAxisView::get_device_names()
912 using namespace MIDI::Name;
914 const std::string model = gui_property (X_("midnam-model-name"));
916 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
917 .document_by_model(model);
919 return midnam->master_device_names(model);
921 return boost::shared_ptr<MasterDeviceNames>();
926 MidiTimeAxisView::build_controller_menu ()
928 using namespace Menu_Helpers;
930 if (controller_menu) {
931 /* it exists and has not been invalidated by a channel mode change */
935 controller_menu = new Menu; // explicitly managed by us
936 MenuList& items (controller_menu->items());
938 /* create several "top level" menu items for sets of controllers (16 at a
939 time), and populate each one with a submenu for each controller+channel
940 combination covering the currently selected channels for this track
943 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
945 /* count the number of selected channels because we will build a different menu
946 structure if there is more than 1 selected.
950 for (uint8_t chn = 0; chn < 16; chn++) {
951 if (selected_channels & (0x0001 << chn)) {
958 using namespace MIDI::Name;
959 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
961 if (device_names && !device_names->controls().empty()) {
962 /* Controllers names available in midnam file, generate fancy menu */
963 unsigned n_items = 0;
964 unsigned n_groups = 0;
966 /* keep track of CC numbers that are added */
967 uint16_t ctl_start = 1;
968 uint16_t ctl_end = 1;
970 MasterDeviceNames::ControlNameLists const& ctllist (device_names->controls());
972 size_t total_ctrls = 0;
973 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
974 boost::shared_ptr<ControlNameList> name_list = l->second;
975 total_ctrls += name_list->controls().size();
978 bool to_top_level = total_ctrls < 32;
980 /* TODO: This is not correct, should look up the currently applicable ControlNameList
981 and only build a menu for that one. */
982 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
983 boost::shared_ptr<ControlNameList> name_list = l->second;
984 Menu* ctl_menu = NULL;
986 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
987 c != name_list->controls().end();) {
988 const uint16_t ctl = c->second->number();
990 /* Skip bank select controllers since they're handled specially */
991 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
994 ctl_menu = controller_menu;
995 } else if (!ctl_menu) {
996 /* Create a new submenu */
997 ctl_menu = manage (new Menu);
1001 MenuList& ctl_items (ctl_menu->items());
1003 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
1005 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
1012 if (!ctl_menu || to_top_level) {
1016 if (++n_items == 32 || ctl < ctl_start || c == name_list->controls().end()) {
1017 /* Submenu has 32 items or we're done, or a new name-list started:
1018 * add it to controller menu and reset */
1019 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), ctl_start, ctl_end), *ctl_menu));
1027 /* No controllers names, generate generic numeric menu */
1028 for (int i = 0; i < 127; i += 32) {
1029 Menu* ctl_menu = manage (new Menu);
1030 MenuList& ctl_items (ctl_menu->items());
1032 for (int ctl = i; ctl < i + 32; ++ctl) {
1033 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1034 /* Skip bank select controllers since they're handled specially */
1039 add_multi_channel_controller_item(
1040 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1042 add_single_channel_controller_item(
1043 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1047 /* Add submenu for this block of controllers to controller menu */
1051 /* skip 0x00 and 0x20 (bank-select) */
1052 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i + 1, i + 31), *ctl_menu));
1055 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i + 31), *ctl_menu));
1063 MidiTimeAxisView::build_note_mode_menu()
1065 using namespace Menu_Helpers;
1067 Menu* mode_menu = manage (new Menu);
1068 MenuList& items = mode_menu->items();
1069 mode_menu->set_name ("ArdourContextMenu");
1071 RadioMenuItem::Group mode_group;
1073 RadioMenuElem (mode_group,_("Sustained"),
1074 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1076 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1077 _note_mode_item->set_active(_note_mode == Sustained);
1080 RadioMenuElem (mode_group, _("Percussive"),
1081 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1082 Percussive, true)));
1083 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1084 _percussion_mode_item->set_active(_note_mode == Percussive);
1090 MidiTimeAxisView::build_color_mode_menu()
1092 using namespace Menu_Helpers;
1094 Menu* mode_menu = manage (new Menu);
1095 MenuList& items = mode_menu->items();
1096 mode_menu->set_name ("ArdourContextMenu");
1098 RadioMenuItem::Group mode_group;
1100 RadioMenuElem (mode_group, _("Meter Colors"),
1101 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1102 MeterColors, false, true, true)));
1103 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1104 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1107 RadioMenuElem (mode_group, _("Channel Colors"),
1108 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1109 ChannelColors, false, true, true)));
1110 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1111 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1114 RadioMenuElem (mode_group, _("Track Color"),
1115 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1116 TrackColor, false, true, true)));
1117 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1118 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1124 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1126 if (apply_to_selection) {
1127 _editor.get_selection().tracks.foreach_midi_time_axis (
1128 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1130 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1132 midi_track()->set_note_mode(mode);
1133 set_gui_property ("note-mode", enum_2_string(_note_mode));
1134 _view->redisplay_track();
1140 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1142 if (apply_to_selection) {
1143 _editor.get_selection().tracks.foreach_midi_time_axis (
1144 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1146 if (_color_mode == mode && !force) {
1150 if (_channel_selector) {
1151 if (mode == ChannelColors) {
1152 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1154 _channel_selector->set_default_channel_color();
1159 set_gui_property ("color-mode", enum_2_string(_color_mode));
1161 _view->redisplay_track();
1167 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1169 if (apply_to_selection) {
1170 _editor.get_selection().tracks.foreach_midi_time_axis (
1171 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1173 if (!_ignore_signals) {
1174 midi_view()->set_note_range(range);
1180 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1182 using namespace MIDI::Name;
1184 if (apply_to_selection) {
1185 _editor.get_selection().tracks.foreach_midi_time_axis (
1186 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1189 // Show existing automation
1190 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1192 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1193 create_automation_child(*i, true);
1196 // Show automation for all controllers named in midnam file
1197 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1198 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1199 device_names && !device_names->controls().empty()) {
1200 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1201 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1202 for (uint32_t chn = 0; chn < 16; ++chn) {
1203 if ((selected_channels & (0x0001 << chn)) == 0) {
1204 // Channel not in use
1208 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1214 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1215 chan_names->control_list_name());
1216 if (!control_names) {
1220 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1221 c != control_names->controls().end();
1223 const uint16_t ctl = c->second->number();
1224 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1225 /* Skip bank select controllers since they're handled specially */
1226 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1227 create_automation_child(param, true);
1234 RouteTimeAxisView::show_all_automation ();
1239 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1241 if (apply_to_selection) {
1242 _editor.get_selection().tracks.foreach_midi_time_axis (
1243 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1246 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1248 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1249 create_automation_child (*i, true);
1253 RouteTimeAxisView::show_existing_automation ();
1257 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1260 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1262 if (param.type() == NullAutomation) {
1266 AutomationTracks::iterator existing = _automation_tracks.find (param);
1268 if (existing != _automation_tracks.end()) {
1270 /* automation track created because we had existing data for
1271 * the processor, but visibility may need to be controlled
1272 * since it will have been set visible by default.
1275 existing->second->set_marked_for_display (show);
1284 boost::shared_ptr<AutomationTimeAxisView> track;
1285 boost::shared_ptr<AutomationControl> control;
1288 switch (param.type()) {
1290 case GainAutomation:
1292 create_gain_automation_child (param, show);
1295 case MuteAutomation:
1296 create_mute_automation_child (param, show);
1299 case PluginAutomation:
1300 /* handled elsewhere */
1303 case MidiCCAutomation:
1304 case MidiPgmChangeAutomation:
1305 case MidiPitchBenderAutomation:
1306 case MidiChannelPressureAutomation:
1307 case MidiNotePressureAutomation:
1308 case MidiSystemExclusiveAutomation:
1309 /* These controllers are region "automation" - they are owned
1310 * by regions (and their MidiModels), not by the track. As a
1311 * result there is no AutomationList/Line for the track, but we create
1312 * a controller for the user to write immediate events, so the editor
1313 * can act as a control surface for the present MIDI controllers.
1315 * TODO: Record manipulation of the controller to regions?
1318 control = _route->automation_control(param, true);
1319 track.reset (new AutomationTimeAxisView (
1322 control ? _route : boost::shared_ptr<Automatable> (),
1329 _route->describe_parameter(param)));
1332 _view->foreach_regionview (
1333 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1336 add_automation_child (param, track, show);
1338 reshow_selection (_editor.get_selection().time);
1343 case PanWidthAutomation:
1344 case PanElevationAutomation:
1345 case PanAzimuthAutomation:
1346 ensure_pan_views (show);
1350 error << "MidiTimeAxisView: unknown automation child "
1351 << EventTypeMap::instance().to_symbol(param) << endmsg;
1356 MidiTimeAxisView::route_active_changed ()
1358 RouteUI::route_active_changed ();
1359 update_control_names();
1363 MidiTimeAxisView::update_control_names ()
1366 if (_route->active()) {
1367 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1368 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1370 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1371 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1373 } else { // MIDI bus (which doesn't exist yet..)
1374 if (_route->active()) {
1375 controls_base_selected_name = "BusControlsBaseSelected";
1376 controls_base_unselected_name = "BusControlsBaseUnselected";
1378 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1379 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1384 controls_ebox.set_name (controls_base_selected_name);
1385 time_axis_frame.set_name (controls_base_selected_name);
1387 controls_ebox.set_name (controls_base_unselected_name);
1388 time_axis_frame.set_name (controls_base_unselected_name);
1393 MidiTimeAxisView::set_note_selection (uint8_t note)
1395 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1397 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1399 /* set_note_selection_region_view() will not work with multiple regions,
1400 * as each individual `foreach` call will clear prior selection.
1401 * Use clear_midi_notes() and add_note_selection_region_view() instead. */
1403 _editor.get_selection().clear_midi_notes();
1405 if (_view->num_selected_regionviews() == 0) {
1406 _view->foreach_regionview (
1407 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1410 _view->foreach_selected_regionview (
1411 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1415 _editor.commit_reversible_selection_op();
1419 MidiTimeAxisView::add_note_selection (uint8_t note)
1421 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1423 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1425 if (_view->num_selected_regionviews() == 0) {
1426 _view->foreach_regionview (
1427 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1430 _view->foreach_selected_regionview (
1431 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1435 _editor.commit_reversible_selection_op();
1439 MidiTimeAxisView::extend_note_selection (uint8_t note)
1441 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1443 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1445 if (_view->num_selected_regionviews() == 0) {
1446 _view->foreach_regionview (
1447 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1450 _view->foreach_selected_regionview (
1451 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1455 _editor.commit_reversible_selection_op();
1459 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1461 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1463 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1465 if (_view->num_selected_regionviews() == 0) {
1466 _view->foreach_regionview (
1467 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1470 _view->foreach_selected_regionview (
1471 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1475 _editor.commit_reversible_selection_op();
1479 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > >& selection)
1481 _view->foreach_regionview (
1482 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1486 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1488 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1492 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1494 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1498 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1500 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1504 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1506 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1510 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection)
1512 Evoral::Sequence<Temporal::Beats>::Notes selected;
1513 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1515 std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > notes;
1517 Evoral::Sequence<Temporal::Beats>::Notes::iterator sel_it;
1518 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1519 notes.insert (*sel_it);
1522 if (!notes.empty()) {
1523 selection.push_back (make_pair ((rv)->region()->id(), notes));
1528 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1530 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1534 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1535 bool changed = false;
1539 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1541 for (uint32_t chn = 0; chn < 16; ++chn) {
1542 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1543 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1549 if ((selected_channels & (0x0001 << chn)) == 0) {
1550 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1551 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1553 changed = track->set_marked_for_display (false) || changed;
1555 changed = track->set_marked_for_display (true) || changed;
1562 /* TODO: Bender, Pressure */
1564 /* invalidate the controller menu, so that we rebuild it next time */
1565 _controller_menu_map.clear ();
1566 delete controller_menu;
1567 controller_menu = 0;
1575 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1577 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1582 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1583 if (i != _controller_menu_map.end()) {
1587 i = _channel_command_menu_map.find (param);
1588 if (i != _channel_command_menu_map.end()) {
1595 boost::shared_ptr<MidiRegion>
1596 MidiTimeAxisView::add_region (samplepos_t f, samplecnt_t length, bool commit)
1598 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1599 MusicSample pos (f, 0);
1602 real_editor->begin_reversible_command (Operations::create_region);
1604 playlist()->clear_changes ();
1606 real_editor->snap_to (pos, RoundNearest);
1608 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1611 plist.add (ARDOUR::Properties::start, 0);
1612 plist.add (ARDOUR::Properties::length, length);
1613 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1615 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1616 /* sets beat position */
1617 region->set_position (pos.sample, pos.division);
1618 playlist()->add_region (region, pos.sample, 1.0, false, pos.division);
1619 _session->add_command (new StatefulDiffCommand (playlist()));
1622 real_editor->commit_reversible_command ();
1625 return boost::dynamic_pointer_cast<MidiRegion>(region);
1629 MidiTimeAxisView::ensure_step_editor ()
1631 if (!_step_editor) {
1632 _step_editor = new StepEditor (_editor, midi_track(), *this);
1637 MidiTimeAxisView::start_step_editing ()
1639 ensure_step_editor ();
1640 _step_editor->start_step_editing ();
1644 MidiTimeAxisView::stop_step_editing ()
1647 _step_editor->stop_step_editing ();
1651 /** @return channel (counted from 0) to add an event to, based on the current setting
1652 * of the channel selector.
1655 MidiTimeAxisView::get_channel_for_add () const
1657 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1659 uint8_t channel = 0;
1661 /* pick the highest selected channel, unless all channels are selected,
1662 which is interpreted to mean channel 1 (zero)
1665 for (uint16_t i = 0; i < 16; ++i) {
1666 if (chn_mask & (1<<i)) {
1672 if (chn_cnt == 16) {
1680 MidiTimeAxisView::note_range_changed ()
1682 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1683 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1687 MidiTimeAxisView::contents_height_changed ()
1689 _range_scroomer->queue_resize ();
1693 MidiTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1695 if (!_editor.internal_editing()) {
1696 // Non-internal paste, paste regions like any other route
1697 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1700 return midi_view()->paste(pos, selection, ctx, sub_num);