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().maybe_use (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::use_midnam_info, this), gui_context());
279 model_changed (gui_property(X_("midnam-model-name")));
280 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
282 controls_vbox.pack_start(_midi_controls_box, false, false);
284 const string color_mode = gui_property ("color-mode");
285 if (!color_mode.empty()) {
286 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
287 if (_channel_selector && _color_mode == ChannelColors) {
288 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
292 set_color_mode (_color_mode, true, false);
294 const string note_mode = gui_property ("note-mode");
295 if (!note_mode.empty()) {
296 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
297 if (_percussion_mode_item) {
298 _percussion_mode_item->set_active (_note_mode == Percussive);
302 /* Look for any GUI object state nodes that represent automation children
303 * that should exist, and create the children.
306 const list<string> gui_ids = gui_object_state().all_ids ();
307 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
310 Evoral::Parameter parameter (0, 0, 0);
312 bool const p = AutomationTimeAxisView::parse_state_id (
313 *i, route_id, has_parameter, parameter);
314 if (p && route_id == _route->id () && has_parameter) {
315 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
316 create_automation_child (parameter, string_to<bool> (visible));
322 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
324 RouteTimeAxisView::processors_changed (c);
325 update_patch_selector ();
329 MidiTimeAxisView::first_idle ()
336 MidiTimeAxisView::~MidiTimeAxisView ()
338 delete _channel_selector;
340 delete _piano_roll_header;
341 _piano_roll_header = 0;
343 delete _range_scroomer;
346 delete controller_menu;
351 MidiTimeAxisView::check_step_edit ()
353 ensure_step_editor ();
354 _step_editor->check_step_edit ();
359 MidiTimeAxisView::use_midnam_info ()
361 std::cerr << "Using MIDNAM info from " << pthread_name() << endl;
362 setup_midnam_patches ();
363 update_patch_selector ();
367 MidiTimeAxisView::setup_midnam_patches ()
369 typedef MIDI::Name::MidiPatchManager PatchManager;
370 PatchManager& patch_manager = PatchManager::instance();
372 _midnam_model_selector.clear_items ();
375 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
376 if (pi && pi->plugin ()->has_midnam ()) {
377 std::string model_name = pi->plugin ()->midnam_model ();
379 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
380 _("Plugin Provided"),
381 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
384 _midnam_model_selector.AddMenuElem(elem);
388 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
389 m != patch_manager.devices_by_manufacturer().end(); ++m) {
390 Menu* menu = Gtk::manage(new Menu);
391 Menu_Helpers::MenuList& items = menu->items();
393 // Build manufacturer submenu
394 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
395 n != m->second.end(); ++n) {
397 if (patch_manager.is_custom_model (n->first)) {
401 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
403 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
406 items.push_back(elem);
408 if (items.empty ()) {
413 // Add manufacturer submenu to selector
414 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
417 if (!get_device_names()) {
418 model_changed ("Generic");
423 MidiTimeAxisView::update_patch_selector ()
425 typedef MIDI::Name::MidiPatchManager PatchManager;
426 PatchManager& patch_manager = PatchManager::instance();
429 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
430 if (pi && pi->plugin ()->has_midnam ()) {
431 std::string model_name = pi->plugin ()->midnam_model ();
432 if (gui_property (X_("midnam-model-name")) != model_name) {
433 /* ensure that "Plugin Provided" is prefixed at the top of the list */
434 if (_midnam_model_selector.items().empty () || _midnam_model_selector.items().begin()->get_label() != _("Plugin Provided")) {
435 setup_midnam_patches ();
437 model_changed (model_name);
442 if (patch_manager.all_models().empty()) {
443 _midnam_model_selector.hide ();
444 _midnam_custom_device_mode_selector.hide ();
446 _midnam_model_selector.show ();
447 if (_midnam_custom_device_mode_selector.items().size() > 1) {
448 _midnam_custom_device_mode_selector.show ();
455 MidiTimeAxisView::model_changed(const std::string& model)
457 set_gui_property (X_("midnam-model-name"), model);
459 typedef MIDI::Name::MidiPatchManager PatchManager;
460 PatchManager& patch_manager = PatchManager::instance();
462 const std::list<std::string> device_modes = patch_manager.custom_device_mode_names_by_model(model);
464 if (patch_manager.is_custom_model (model)) {
465 _midnam_model_selector.set_text(_("Plugin Provided"));
467 _midnam_model_selector.set_text(model);
469 _midnam_custom_device_mode_selector.clear_items();
471 for (std::list<std::string>::const_iterator i = device_modes.begin();
472 i != device_modes.end(); ++i) {
473 _midnam_custom_device_mode_selector.AddMenuElem(
474 Gtk::Menu_Helpers::MenuElem(
475 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
479 if (!device_modes.empty()) {
480 custom_device_mode_changed(device_modes.front());
483 if (device_modes.size() > 1) {
484 _midnam_custom_device_mode_selector.show();
486 _midnam_custom_device_mode_selector.hide();
489 // now this is a real bad hack
490 if (device_modes.size() > 0) {
491 _route->instrument_info().set_external_instrument (model, device_modes.front());
493 _route->instrument_info().set_external_instrument (model, "");
496 // Rebuild controller menu
497 _controller_menu_map.clear ();
498 delete controller_menu;
500 build_automation_action_menu(false);
502 if (patch_change_dialog ()) {
503 patch_change_dialog ()->refresh ();
508 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
510 const std::string model = gui_property (X_("midnam-model-name"));
512 set_gui_property (X_("midnam-custom-device-mode"), mode);
513 _midnam_custom_device_mode_selector.set_text(mode);
514 _route->instrument_info().set_external_instrument (model, mode);
518 MidiTimeAxisView::midi_view()
520 return dynamic_cast<MidiStreamView*>(_view);
524 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
526 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
527 _midi_controls_box.show ();
529 _midi_controls_box.hide();
532 if (h >= KEYBOARD_MIN_HEIGHT) {
533 if (is_track() && _range_scroomer) {
534 _range_scroomer->show();
536 if (is_track() && _piano_roll_header) {
537 _piano_roll_header->show();
540 if (is_track() && _range_scroomer) {
541 _range_scroomer->hide();
543 if (is_track() && _piano_roll_header) {
544 _piano_roll_header->hide();
548 /* We need to do this after changing visibility of our stuff, as it will
549 eventually trigger a call to Editor::reset_controls_layout_width(),
550 which needs to know if we have just shown or hidden a scroomer /
553 RouteTimeAxisView::set_height (h, m);
557 MidiTimeAxisView::append_extra_display_menu_items ()
559 using namespace Menu_Helpers;
561 MenuList& items = display_menu->items();
564 Menu *range_menu = manage(new Menu);
565 MenuList& range_items = range_menu->items();
566 range_menu->set_name ("ArdourContextMenu");
568 range_items.push_back (
569 MenuElem (_("Show Full Range"),
570 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
571 MidiStreamView::FullRange, true)));
573 range_items.push_back (
574 MenuElem (_("Fit Contents"),
575 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
576 MidiStreamView::ContentsRange, true)));
578 items.push_back (MenuElem (_("Note Range"), *range_menu));
579 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
580 items.push_back (MenuElem (_("Channel Selector..."),
581 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
583 items.push_back (MenuElem (_("Patch Selector..."),
584 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
586 items.push_back (MenuElem (_("Color Mode"), *build_color_mode_menu ()));
588 items.push_back (SeparatorElem ());
592 MidiTimeAxisView::toggle_channel_selector ()
594 if (!_channel_selector) {
595 _channel_selector = new MidiChannelSelectorWindow (midi_track());
597 if (_color_mode == ChannelColors) {
598 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
600 _channel_selector->set_default_channel_color ();
603 _channel_selector->show_all ();
605 _channel_selector->cycle_visibility ();
610 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
612 using namespace Menu_Helpers;
614 /* If we have a controller menu, we need to detach it before
615 RouteTimeAxis::build_automation_action_menu destroys the
616 menu it is attached to. Otherwise GTK destroys
617 controller_menu's gobj, meaning that it can't be reattached
618 below. See bug #3134.
621 if (controller_menu) {
622 detach_menu (*controller_menu);
625 _channel_command_menu_map.clear ();
626 RouteTimeAxisView::build_automation_action_menu (for_selection);
628 MenuList& automation_items = automation_action_menu->items();
630 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
632 if (selected_channels != 0) {
634 automation_items.push_back (SeparatorElem());
636 /* these 2 MIDI "command" types are semantically more like automation
637 than note data, but they are not MIDI controllers. We give them
638 special status in this menu, since they will not show up in the
639 controller list and anyone who actually knows something about MIDI
640 (!) would not expect to find them there.
643 add_channel_command_menu_item (
644 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
645 automation_items.back().set_sensitive (
646 !for_selection || _editor.get_selection().tracks.size() == 1);
647 add_channel_command_menu_item (
648 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
649 automation_items.back().set_sensitive (
650 !for_selection || _editor.get_selection().tracks.size() == 1);
652 /* now all MIDI controllers. Always offer the possibility that we will
653 rebuild the controllers menu since it might need to be updated after
654 a channel mode change or other change. Also detach it first in case
655 it has been used anywhere else.
658 build_controller_menu ();
660 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
662 if (!poly_pressure_menu) {
663 poly_pressure_menu = new Gtk::Menu;
666 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
668 automation_items.back().set_sensitive (
669 !for_selection || _editor.get_selection().tracks.size() == 1);
671 automation_items.push_back (
672 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
673 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
678 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
680 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
682 for (uint8_t chn = 0; chn < 16; chn++) {
683 if (selected_channels & (0x0001 << chn)) {
685 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
686 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
689 menu->set_active (yn);
696 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
698 AutomationType auto_type,
701 using namespace Menu_Helpers;
703 /* count the number of selected channels because we will build a different menu
704 structure if there is more than 1 selected.
707 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
710 for (uint8_t chn = 0; chn < 16; chn++) {
711 if (selected_channels & (0x0001 << chn)) {
720 /* multiple channels - create a submenu, with 1 item per channel */
722 Menu* chn_menu = manage (new Menu);
723 MenuList& chn_items (chn_menu->items());
724 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
726 /* add a couple of items to hide/show all of them */
728 chn_items.push_back (
729 MenuElem (_("Hide all channels"),
730 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
731 false, param_without_channel)));
732 chn_items.push_back (
733 MenuElem (_("Show all channels"),
734 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
735 true, param_without_channel)));
737 for (uint8_t chn = 0; chn < 16; chn++) {
738 if (selected_channels & (0x0001 << chn)) {
740 /* for each selected channel, add a menu item for this controller */
742 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
743 chn_items.push_back (
744 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
745 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
746 fully_qualified_param)));
748 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
749 bool visible = false;
752 if (track->marked_for_display()) {
757 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
758 _channel_command_menu_map[fully_qualified_param] = cmi;
759 cmi->set_active (visible);
763 /* now create an item in the parent menu that has the per-channel list as a submenu */
765 items.push_back (MenuElem (label, *chn_menu));
769 /* just one channel - create a single menu item for this command+channel combination*/
771 for (uint8_t chn = 0; chn < 16; chn++) {
772 if (selected_channels & (0x0001 << chn)) {
774 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
776 CheckMenuElem (label,
777 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
778 fully_qualified_param)));
780 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
781 bool visible = false;
784 if (track->marked_for_display()) {
789 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
790 _channel_command_menu_map[fully_qualified_param] = cmi;
791 cmi->set_active (visible);
793 /* one channel only */
800 /** Add a single menu item for a controller on one channel. */
802 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
804 const std::string& name)
806 using namespace Menu_Helpers;
808 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
809 for (uint8_t chn = 0; chn < 16; chn++) {
810 if (selected_channels & (0x0001 << chn)) {
812 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
813 ctl_items.push_back (
815 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
817 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
818 fully_qualified_param)));
819 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
821 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
822 fully_qualified_param);
824 bool visible = false;
826 if (track->marked_for_display()) {
831 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
832 _controller_menu_map[fully_qualified_param] = cmi;
833 cmi->set_active (visible);
835 /* one channel only */
841 /** Add a submenu with 1 item per channel for a controller on many channels. */
843 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
845 const std::string& name)
847 using namespace Menu_Helpers;
849 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
851 Menu* chn_menu = manage (new Menu);
852 MenuList& chn_items (chn_menu->items());
854 /* add a couple of items to hide/show this controller on all channels */
856 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
857 chn_items.push_back (
858 MenuElem (_("Hide all channels"),
859 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
860 false, param_without_channel)));
861 chn_items.push_back (
862 MenuElem (_("Show all channels"),
863 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
864 true, param_without_channel)));
866 for (uint8_t chn = 0; chn < 16; chn++) {
867 if (selected_channels & (0x0001 << chn)) {
869 /* for each selected channel, add a menu item for this controller */
871 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
872 chn_items.push_back (
873 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
874 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
875 fully_qualified_param)));
877 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
878 fully_qualified_param);
879 bool visible = false;
882 if (track->marked_for_display()) {
887 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
888 _controller_menu_map[fully_qualified_param] = cmi;
889 cmi->set_active (visible);
893 /* add the per-channel menu to the list of controllers, with the name of the controller */
894 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
896 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
899 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
900 MidiTimeAxisView::get_device_mode()
902 using namespace MIDI::Name;
904 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
906 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
909 return device_names->custom_device_mode_by_name(
910 gui_property (X_("midnam-custom-device-mode")));
913 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
914 MidiTimeAxisView::get_device_names()
916 using namespace MIDI::Name;
918 const std::string model = gui_property (X_("midnam-model-name"));
920 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
921 .document_by_model(model);
923 return midnam->master_device_names(model);
925 return boost::shared_ptr<MasterDeviceNames>();
930 MidiTimeAxisView::build_controller_menu ()
932 using namespace Menu_Helpers;
934 if (controller_menu) {
935 /* it exists and has not been invalidated by a channel mode change */
939 controller_menu = new Menu; // explicitly managed by us
940 MenuList& items (controller_menu->items());
942 /* create several "top level" menu items for sets of controllers (16 at a
943 time), and populate each one with a submenu for each controller+channel
944 combination covering the currently selected channels for this track
947 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
949 /* count the number of selected channels because we will build a different menu
950 structure if there is more than 1 selected.
954 for (uint8_t chn = 0; chn < 16; chn++) {
955 if (selected_channels & (0x0001 << chn)) {
962 using namespace MIDI::Name;
963 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
965 if (device_names && !device_names->controls().empty()) {
966 /* Controllers names available in midnam file, generate fancy menu */
967 unsigned n_items = 0;
968 unsigned n_groups = 0;
970 /* keep track of CC numbers that are added */
971 uint16_t ctl_start = 1;
972 uint16_t ctl_end = 1;
974 MasterDeviceNames::ControlNameLists const& ctllist (device_names->controls());
976 size_t total_ctrls = 0;
977 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
978 boost::shared_ptr<ControlNameList> name_list = l->second;
979 total_ctrls += name_list->controls().size();
982 bool to_top_level = total_ctrls < 32;
984 /* TODO: This is not correct, should look up the currently applicable ControlNameList
985 and only build a menu for that one. */
986 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
987 boost::shared_ptr<ControlNameList> name_list = l->second;
988 Menu* ctl_menu = NULL;
990 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
991 c != name_list->controls().end();) {
992 const uint16_t ctl = c->second->number();
994 /* Skip bank select controllers since they're handled specially */
995 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
998 ctl_menu = controller_menu;
999 } else if (!ctl_menu) {
1000 /* Create a new submenu */
1001 ctl_menu = manage (new Menu);
1005 MenuList& ctl_items (ctl_menu->items());
1007 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
1009 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
1016 if (!ctl_menu || to_top_level) {
1020 if (++n_items == 32 || ctl < ctl_start || c == name_list->controls().end()) {
1021 /* Submenu has 32 items or we're done, or a new name-list started:
1022 * add it to controller menu and reset */
1023 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), ctl_start, ctl_end), *ctl_menu));
1031 /* No controllers names, generate generic numeric menu */
1032 for (int i = 0; i < 127; i += 32) {
1033 Menu* ctl_menu = manage (new Menu);
1034 MenuList& ctl_items (ctl_menu->items());
1036 for (int ctl = i; ctl < i + 32; ++ctl) {
1037 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1038 /* Skip bank select controllers since they're handled specially */
1043 add_multi_channel_controller_item(
1044 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1046 add_single_channel_controller_item(
1047 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1051 /* Add submenu for this block of controllers to controller menu */
1055 /* skip 0x00 and 0x20 (bank-select) */
1056 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i + 1, i + 31), *ctl_menu));
1059 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i + 31), *ctl_menu));
1067 MidiTimeAxisView::build_note_mode_menu()
1069 using namespace Menu_Helpers;
1071 Menu* mode_menu = manage (new Menu);
1072 MenuList& items = mode_menu->items();
1073 mode_menu->set_name ("ArdourContextMenu");
1075 RadioMenuItem::Group mode_group;
1077 RadioMenuElem (mode_group,_("Sustained"),
1078 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1080 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1081 _note_mode_item->set_active(_note_mode == Sustained);
1084 RadioMenuElem (mode_group, _("Percussive"),
1085 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1086 Percussive, true)));
1087 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1088 _percussion_mode_item->set_active(_note_mode == Percussive);
1094 MidiTimeAxisView::build_color_mode_menu()
1096 using namespace Menu_Helpers;
1098 Menu* mode_menu = manage (new Menu);
1099 MenuList& items = mode_menu->items();
1100 mode_menu->set_name ("ArdourContextMenu");
1102 RadioMenuItem::Group mode_group;
1104 RadioMenuElem (mode_group, _("Meter Colors"),
1105 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1106 MeterColors, false, true, true)));
1107 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1108 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1111 RadioMenuElem (mode_group, _("Channel Colors"),
1112 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1113 ChannelColors, false, true, true)));
1114 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1115 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1118 RadioMenuElem (mode_group, _("Track Color"),
1119 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1120 TrackColor, false, true, true)));
1121 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1122 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1128 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1130 if (apply_to_selection) {
1131 _editor.get_selection().tracks.foreach_midi_time_axis (
1132 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1134 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1136 midi_track()->set_note_mode(mode);
1137 set_gui_property ("note-mode", enum_2_string(_note_mode));
1138 _view->redisplay_track();
1144 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1146 if (apply_to_selection) {
1147 _editor.get_selection().tracks.foreach_midi_time_axis (
1148 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1150 if (_color_mode == mode && !force) {
1154 if (_channel_selector) {
1155 if (mode == ChannelColors) {
1156 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1158 _channel_selector->set_default_channel_color();
1163 set_gui_property ("color-mode", enum_2_string(_color_mode));
1165 _view->redisplay_track();
1171 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1173 if (apply_to_selection) {
1174 _editor.get_selection().tracks.foreach_midi_time_axis (
1175 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1177 if (!_ignore_signals) {
1178 midi_view()->set_note_range(range);
1184 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1186 using namespace MIDI::Name;
1188 if (apply_to_selection) {
1189 _editor.get_selection().tracks.foreach_midi_time_axis (
1190 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1193 // Show existing automation
1194 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1196 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1197 create_automation_child(*i, true);
1200 // Show automation for all controllers named in midnam file
1201 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1202 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1203 device_names && !device_names->controls().empty()) {
1204 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1205 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1206 for (uint32_t chn = 0; chn < 16; ++chn) {
1207 if ((selected_channels & (0x0001 << chn)) == 0) {
1208 // Channel not in use
1212 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1218 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1219 chan_names->control_list_name());
1220 if (!control_names) {
1224 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1225 c != control_names->controls().end();
1227 const uint16_t ctl = c->second->number();
1228 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1229 /* Skip bank select controllers since they're handled specially */
1230 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1231 create_automation_child(param, true);
1238 RouteTimeAxisView::show_all_automation ();
1243 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1245 if (apply_to_selection) {
1246 _editor.get_selection().tracks.foreach_midi_time_axis (
1247 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1250 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1252 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1253 create_automation_child (*i, true);
1257 RouteTimeAxisView::show_existing_automation ();
1261 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1264 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1266 if (param.type() == NullAutomation) {
1270 AutomationTracks::iterator existing = _automation_tracks.find (param);
1272 if (existing != _automation_tracks.end()) {
1274 /* automation track created because we had existing data for
1275 * the processor, but visibility may need to be controlled
1276 * since it will have been set visible by default.
1279 existing->second->set_marked_for_display (show);
1288 boost::shared_ptr<AutomationTimeAxisView> track;
1289 boost::shared_ptr<AutomationControl> control;
1292 switch (param.type()) {
1294 case GainAutomation:
1296 create_gain_automation_child (param, show);
1299 case MuteAutomation:
1300 create_mute_automation_child (param, show);
1303 case PluginAutomation:
1304 /* handled elsewhere */
1307 case MidiCCAutomation:
1308 case MidiPgmChangeAutomation:
1309 case MidiPitchBenderAutomation:
1310 case MidiChannelPressureAutomation:
1311 case MidiNotePressureAutomation:
1312 case MidiSystemExclusiveAutomation:
1313 /* These controllers are region "automation" - they are owned
1314 * by regions (and their MidiModels), not by the track. As a
1315 * result there is no AutomationList/Line for the track, but we create
1316 * a controller for the user to write immediate events, so the editor
1317 * can act as a control surface for the present MIDI controllers.
1319 * TODO: Record manipulation of the controller to regions?
1322 control = _route->automation_control(param, true);
1323 track.reset (new AutomationTimeAxisView (
1326 control ? _route : boost::shared_ptr<Automatable> (),
1333 _route->describe_parameter(param)));
1336 _view->foreach_regionview (
1337 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1340 add_automation_child (param, track, show);
1342 reshow_selection (_editor.get_selection().time);
1347 case PanWidthAutomation:
1348 case PanElevationAutomation:
1349 case PanAzimuthAutomation:
1350 ensure_pan_views (show);
1354 error << "MidiTimeAxisView: unknown automation child "
1355 << EventTypeMap::instance().to_symbol(param) << endmsg;
1360 MidiTimeAxisView::route_active_changed ()
1362 RouteUI::route_active_changed ();
1363 update_control_names();
1367 MidiTimeAxisView::update_control_names ()
1370 if (_route->active()) {
1371 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1372 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1374 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1375 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1377 } else { // MIDI bus (which doesn't exist yet..)
1378 if (_route->active()) {
1379 controls_base_selected_name = "BusControlsBaseSelected";
1380 controls_base_unselected_name = "BusControlsBaseUnselected";
1382 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1383 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1388 controls_ebox.set_name (controls_base_selected_name);
1389 time_axis_frame.set_name (controls_base_selected_name);
1391 controls_ebox.set_name (controls_base_unselected_name);
1392 time_axis_frame.set_name (controls_base_unselected_name);
1397 MidiTimeAxisView::set_note_selection (uint8_t note)
1399 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1401 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1403 /* set_note_selection_region_view() will not work with multiple regions,
1404 * as each individual `foreach` call will clear prior selection.
1405 * Use clear_midi_notes() and add_note_selection_region_view() instead. */
1407 _editor.get_selection().clear_midi_notes();
1409 if (_view->num_selected_regionviews() == 0) {
1410 _view->foreach_regionview (
1411 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1414 _view->foreach_selected_regionview (
1415 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1419 _editor.commit_reversible_selection_op();
1423 MidiTimeAxisView::add_note_selection (uint8_t note)
1425 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1427 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1429 if (_view->num_selected_regionviews() == 0) {
1430 _view->foreach_regionview (
1431 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1434 _view->foreach_selected_regionview (
1435 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1439 _editor.commit_reversible_selection_op();
1443 MidiTimeAxisView::extend_note_selection (uint8_t note)
1445 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1447 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1449 if (_view->num_selected_regionviews() == 0) {
1450 _view->foreach_regionview (
1451 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1454 _view->foreach_selected_regionview (
1455 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1459 _editor.commit_reversible_selection_op();
1463 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1465 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1467 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1469 if (_view->num_selected_regionviews() == 0) {
1470 _view->foreach_regionview (
1471 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1474 _view->foreach_selected_regionview (
1475 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1479 _editor.commit_reversible_selection_op();
1483 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > >& selection)
1485 _view->foreach_regionview (
1486 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1490 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1492 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1496 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1498 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1502 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1504 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1508 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1510 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1514 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection)
1516 Evoral::Sequence<Temporal::Beats>::Notes selected;
1517 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1519 std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > notes;
1521 Evoral::Sequence<Temporal::Beats>::Notes::iterator sel_it;
1522 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1523 notes.insert (*sel_it);
1526 if (!notes.empty()) {
1527 selection.push_back (make_pair ((rv)->region()->id(), notes));
1532 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1534 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1538 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1539 bool changed = false;
1543 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1545 for (uint32_t chn = 0; chn < 16; ++chn) {
1546 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1547 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1553 if ((selected_channels & (0x0001 << chn)) == 0) {
1554 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1555 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1557 changed = track->set_marked_for_display (false) || changed;
1559 changed = track->set_marked_for_display (true) || changed;
1566 /* TODO: Bender, Pressure */
1568 /* invalidate the controller menu, so that we rebuild it next time */
1569 _controller_menu_map.clear ();
1570 delete controller_menu;
1571 controller_menu = 0;
1579 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1581 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1586 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1587 if (i != _controller_menu_map.end()) {
1591 i = _channel_command_menu_map.find (param);
1592 if (i != _channel_command_menu_map.end()) {
1599 boost::shared_ptr<MidiRegion>
1600 MidiTimeAxisView::add_region (samplepos_t f, samplecnt_t length, bool commit)
1602 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1603 MusicSample pos (f, 0);
1606 real_editor->begin_reversible_command (Operations::create_region);
1608 playlist()->clear_changes ();
1610 real_editor->snap_to (pos, RoundNearest);
1612 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1615 plist.add (ARDOUR::Properties::start, 0);
1616 plist.add (ARDOUR::Properties::length, length);
1617 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1619 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1620 /* sets beat position */
1621 region->set_position (pos.sample, pos.division);
1622 playlist()->add_region (region, pos.sample, 1.0, false, pos.division);
1623 _session->add_command (new StatefulDiffCommand (playlist()));
1626 real_editor->commit_reversible_command ();
1629 return boost::dynamic_pointer_cast<MidiRegion>(region);
1633 MidiTimeAxisView::ensure_step_editor ()
1635 if (!_step_editor) {
1636 _step_editor = new StepEditor (_editor, midi_track(), *this);
1641 MidiTimeAxisView::start_step_editing ()
1643 ensure_step_editor ();
1644 _step_editor->start_step_editing ();
1648 MidiTimeAxisView::stop_step_editing ()
1651 _step_editor->stop_step_editing ();
1655 /** @return channel (counted from 0) to add an event to, based on the current setting
1656 * of the channel selector.
1659 MidiTimeAxisView::get_channel_for_add () const
1661 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1663 uint8_t channel = 0;
1665 /* pick the highest selected channel, unless all channels are selected,
1666 which is interpreted to mean channel 1 (zero)
1669 for (uint16_t i = 0; i < 16; ++i) {
1670 if (chn_mask & (1<<i)) {
1676 if (chn_cnt == 16) {
1684 MidiTimeAxisView::note_range_changed ()
1686 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1687 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1691 MidiTimeAxisView::contents_height_changed ()
1693 _range_scroomer->queue_resize ();
1697 MidiTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1699 if (!_editor.internal_editing()) {
1700 // Non-internal paste, paste regions like any other route
1701 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1704 return midi_view()->paste(pos, selection, ctx, sub_num);