2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/plugin_insert.h"
54 #include "ardour/profile.h"
55 #include "ardour/region.h"
56 #include "ardour/region_factory.h"
57 #include "ardour/route.h"
58 #include "ardour/session.h"
59 #include "ardour/session_object.h"
60 #include "ardour/source.h"
61 #include "ardour/track.h"
62 #include "ardour/types.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
89 #include "note_base.h"
91 #include "ardour/midi_track.h"
95 using namespace ARDOUR;
96 using namespace ARDOUR_UI_UTILS;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
103 // Minimum height at which a control is displayed
104 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
105 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
107 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
108 : SessionHandlePtr (sess)
109 , RouteTimeAxisView (ed, sess, canvas)
110 , _ignore_signals(false)
112 , _piano_roll_header(0)
113 , _note_mode(Sustained)
115 , _percussion_mode_item(0)
116 , _color_mode(MeterColors)
117 , _meter_color_mode_item(0)
118 , _channel_color_mode_item(0)
119 , _track_color_mode_item(0)
120 , _channel_selector (0)
121 , _step_edit_item (0)
122 , controller_menu (0)
123 , poly_pressure_menu (0)
126 _midnam_model_selector.disable_scrolling();
127 _midnam_custom_device_mode_selector.disable_scrolling();
131 MidiTimeAxisView::set_note_highlight (uint8_t note) {
132 _piano_roll_header->set_note_highlight (note);
136 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
140 _view = new MidiStreamView (*this);
143 _piano_roll_header = new PianoRollHeader(*midi_view());
144 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
145 _range_scroomer->DoubleClicked.connect (
146 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
147 MidiStreamView::ContentsRange, false));
150 /* This next call will result in our height being set up, so it must come after
151 the creation of the piano roll / range scroomer as their visibility is set up
154 RouteTimeAxisView::set_route (rt);
156 _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
158 subplugin_menu.set_name ("ArdourContextMenu");
160 if (!gui_property ("note-range-min").empty ()) {
161 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
162 atoi (gui_property ("note-range-max").c_str()),
166 _view->ContentsHeightChanged.connect (
167 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
169 ignore_toggle = false;
171 if (is_midi_track()) {
172 _note_mode = midi_track()->note_mode();
175 /* if set_state above didn't create a gain automation child, we need to make one */
176 if (automation_child (GainAutomation) == 0) {
177 create_automation_child (GainAutomation, false);
180 /* if set_state above didn't create a mute automation child, we need to make one */
181 if (automation_child (MuteAutomation) == 0) {
182 create_automation_child (MuteAutomation, false);
185 if (_route->panner_shell()) {
186 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
189 /* map current state of the route */
190 ensure_pan_views (false);
191 update_control_names();
192 processors_changed (RouteProcessorChange ());
194 _route->processors_changed.connect (*this, invalidator (*this),
195 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
199 _piano_roll_header->SetNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
201 _piano_roll_header->AddNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
203 _piano_roll_header->ExtendNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
205 _piano_roll_header->ToggleNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
208 /* Update StreamView during scroomer drags.*/
210 _range_scroomer->DragStarting.connect (
211 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
212 _range_scroomer->DragFinishing.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
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 midi_view()->NoteRangeChanged.connect (
238 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
240 /* ask for notifications of any new RegionViews */
241 _view->RegionViewAdded.connect (
242 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
244 if (!_editor.have_idled()) {
245 /* first idle will do what we need */
251 if (gui_property (X_("midnam-model-name")).empty()) {
252 set_gui_property (X_("midnam-model-name"), "Generic");
255 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
256 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
258 set_gui_property (X_("midnam-custom-device-mode"),
259 *device_names->custom_device_mode_names().begin());
263 set_tooltip (_midnam_model_selector, _("External MIDI Device"));
264 set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
266 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
267 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
269 _midi_controls_box.set_homogeneous(false);
270 _midi_controls_box.set_border_width (2);
272 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
273 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
276 setup_midnam_patches ();
277 update_patch_selector ();
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_is_affirmative (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 ();
358 MidiTimeAxisView::setup_midnam_patches ()
360 typedef MIDI::Name::MidiPatchManager PatchManager;
361 PatchManager& patch_manager = PatchManager::instance();
363 _midnam_model_selector.clear_items ();
364 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
365 m != patch_manager.devices_by_manufacturer().end(); ++m) {
366 Menu* menu = Gtk::manage(new Menu);
367 Menu_Helpers::MenuList& items = menu->items();
369 // Build manufacturer submenu
370 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
371 n != m->second.end(); ++n) {
372 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
374 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
377 items.push_back(elem);
380 // Add manufacturer submenu to selector
381 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
384 if (!get_device_names()) {
385 model_changed ("Generic");
390 MidiTimeAxisView::drop_instrument_ref ()
392 midnam_connection.drop_connections ();
395 MidiTimeAxisView::start_scroomer_update ()
397 _note_range_changed_connection.disconnect();
398 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
399 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
402 MidiTimeAxisView::stop_scroomer_update ()
404 _note_range_changed_connection.disconnect();
408 MidiTimeAxisView::update_patch_selector ()
410 typedef MIDI::Name::MidiPatchManager PatchManager;
411 PatchManager& patch_manager = PatchManager::instance();
413 bool pluginprovided = false;
415 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
416 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
417 if (pi && pi->plugin ()->has_midnam ()) {
418 midnam_connection.drop_connections ();
419 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
420 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
422 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
423 boost::bind (&Plugin::read_midnam, pi->plugin ()),
426 pluginprovided = true;
427 std::string model_name = pi->plugin ()->midnam_model ();
428 if (gui_property (X_("midnam-model-name")) != model_name) {
429 model_changed (model_name);
434 if (patch_manager.all_models().empty() || pluginprovided) {
435 _midnam_model_selector.hide ();
436 _midnam_custom_device_mode_selector.hide ();
438 _midnam_model_selector.show ();
439 _midnam_custom_device_mode_selector.show ();
444 MidiTimeAxisView::model_changed(const std::string& model)
446 set_gui_property (X_("midnam-model-name"), model);
448 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
449 .custom_device_mode_names_by_model(model);
451 _midnam_model_selector.set_text(model);
452 _midnam_custom_device_mode_selector.clear_items();
454 for (std::list<std::string>::const_iterator i = device_modes.begin();
455 i != device_modes.end(); ++i) {
456 _midnam_custom_device_mode_selector.AddMenuElem(
457 Gtk::Menu_Helpers::MenuElem(
458 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
462 if (!device_modes.empty()) {
463 custom_device_mode_changed(device_modes.front());
466 if (device_modes.size() > 1) {
467 _midnam_custom_device_mode_selector.show();
469 _midnam_custom_device_mode_selector.hide();
472 // now this is a real bad hack
473 if (device_modes.size() > 0) {
474 _route->instrument_info().set_external_instrument (model, device_modes.front());
476 _route->instrument_info().set_external_instrument (model, "");
479 // Rebuild controller menu
480 _controller_menu_map.clear ();
481 delete controller_menu;
483 build_automation_action_menu(false);
487 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
489 const std::string model = gui_property (X_("midnam-model-name"));
491 set_gui_property (X_("midnam-custom-device-mode"), mode);
492 _midnam_custom_device_mode_selector.set_text(mode);
493 _route->instrument_info().set_external_instrument (model, mode);
497 MidiTimeAxisView::midi_view()
499 return dynamic_cast<MidiStreamView*>(_view);
503 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
505 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
506 _midi_controls_box.show ();
508 _midi_controls_box.hide();
511 if (h >= KEYBOARD_MIN_HEIGHT) {
512 if (is_track() && _range_scroomer) {
513 _range_scroomer->show();
515 if (is_track() && _piano_roll_header) {
516 _piano_roll_header->show();
519 if (is_track() && _range_scroomer) {
520 _range_scroomer->hide();
522 if (is_track() && _piano_roll_header) {
523 _piano_roll_header->hide();
527 /* We need to do this after changing visibility of our stuff, as it will
528 eventually trigger a call to Editor::reset_controls_layout_width(),
529 which needs to know if we have just shown or hidden a scroomer /
532 RouteTimeAxisView::set_height (h, m);
536 MidiTimeAxisView::append_extra_display_menu_items ()
538 using namespace Menu_Helpers;
540 MenuList& items = display_menu->items();
543 Menu *range_menu = manage(new Menu);
544 MenuList& range_items = range_menu->items();
545 range_menu->set_name ("ArdourContextMenu");
547 range_items.push_back (
548 MenuElem (_("Show Full Range"),
549 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
550 MidiStreamView::FullRange, true)));
552 range_items.push_back (
553 MenuElem (_("Fit Contents"),
554 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
555 MidiStreamView::ContentsRange, true)));
557 items.push_back (MenuElem (_("Note Range"), *range_menu));
558 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
559 items.push_back (MenuElem (_("Channel Selector"),
560 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
562 items.push_back (MenuElem (_("Select Patch"), *build_patch_menu()));
564 color_mode_menu = build_color_mode_menu();
565 if (color_mode_menu) {
566 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
569 items.push_back (SeparatorElem ());
573 MidiTimeAxisView::toggle_channel_selector ()
575 if (!_channel_selector) {
576 _channel_selector = new MidiChannelSelectorWindow (midi_track());
578 if (_color_mode == ChannelColors) {
579 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
581 _channel_selector->set_default_channel_color ();
584 _channel_selector->show_all ();
586 _channel_selector->cycle_visibility ();
591 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
593 using namespace Menu_Helpers;
595 /* If we have a controller menu, we need to detach it before
596 RouteTimeAxis::build_automation_action_menu destroys the
597 menu it is attached to. Otherwise GTK destroys
598 controller_menu's gobj, meaning that it can't be reattached
599 below. See bug #3134.
602 if (controller_menu) {
603 detach_menu (*controller_menu);
606 _channel_command_menu_map.clear ();
607 RouteTimeAxisView::build_automation_action_menu (for_selection);
609 MenuList& automation_items = automation_action_menu->items();
611 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
613 if (selected_channels != 0) {
615 automation_items.push_back (SeparatorElem());
617 /* these 2 MIDI "command" types are semantically more like automation
618 than note data, but they are not MIDI controllers. We give them
619 special status in this menu, since they will not show up in the
620 controller list and anyone who actually knows something about MIDI
621 (!) would not expect to find them there.
624 add_channel_command_menu_item (
625 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
626 automation_items.back().set_sensitive (
627 !for_selection || _editor.get_selection().tracks.size() == 1);
628 add_channel_command_menu_item (
629 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
630 automation_items.back().set_sensitive (
631 !for_selection || _editor.get_selection().tracks.size() == 1);
633 /* now all MIDI controllers. Always offer the possibility that we will
634 rebuild the controllers menu since it might need to be updated after
635 a channel mode change or other change. Also detach it first in case
636 it has been used anywhere else.
639 build_controller_menu ();
641 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
643 if (!poly_pressure_menu) {
644 poly_pressure_menu = new Gtk::Menu;
647 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
649 automation_items.back().set_sensitive (
650 !for_selection || _editor.get_selection().tracks.size() == 1);
652 automation_items.push_back (
653 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
654 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
659 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
661 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
663 for (uint8_t chn = 0; chn < 16; chn++) {
664 if (selected_channels & (0x0001 << chn)) {
666 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
667 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
670 menu->set_active (yn);
677 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
679 AutomationType auto_type,
682 using namespace Menu_Helpers;
684 /* count the number of selected channels because we will build a different menu
685 structure if there is more than 1 selected.
688 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
691 for (uint8_t chn = 0; chn < 16; chn++) {
692 if (selected_channels & (0x0001 << chn)) {
701 /* multiple channels - create a submenu, with 1 item per channel */
703 Menu* chn_menu = manage (new Menu);
704 MenuList& chn_items (chn_menu->items());
705 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
707 /* add a couple of items to hide/show all of them */
709 chn_items.push_back (
710 MenuElem (_("Hide all channels"),
711 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
712 false, param_without_channel)));
713 chn_items.push_back (
714 MenuElem (_("Show all channels"),
715 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
716 true, param_without_channel)));
718 for (uint8_t chn = 0; chn < 16; chn++) {
719 if (selected_channels & (0x0001 << chn)) {
721 /* for each selected channel, add a menu item for this controller */
723 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
724 chn_items.push_back (
725 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
726 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
727 fully_qualified_param)));
729 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
730 bool visible = false;
733 if (track->marked_for_display()) {
738 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
739 _channel_command_menu_map[fully_qualified_param] = cmi;
740 cmi->set_active (visible);
744 /* now create an item in the parent menu that has the per-channel list as a submenu */
746 items.push_back (MenuElem (label, *chn_menu));
750 /* just one channel - create a single menu item for this command+channel combination*/
752 for (uint8_t chn = 0; chn < 16; chn++) {
753 if (selected_channels & (0x0001 << chn)) {
755 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
757 CheckMenuElem (label,
758 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
759 fully_qualified_param)));
761 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
762 bool visible = false;
765 if (track->marked_for_display()) {
770 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
771 _channel_command_menu_map[fully_qualified_param] = cmi;
772 cmi->set_active (visible);
774 /* one channel only */
781 /** Add a single menu item for a controller on one channel. */
783 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
785 const std::string& name)
787 using namespace Menu_Helpers;
789 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
790 for (uint8_t chn = 0; chn < 16; chn++) {
791 if (selected_channels & (0x0001 << chn)) {
793 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
794 ctl_items.push_back (
796 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
798 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
799 fully_qualified_param)));
800 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
802 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
803 fully_qualified_param);
805 bool visible = false;
807 if (track->marked_for_display()) {
812 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
813 _controller_menu_map[fully_qualified_param] = cmi;
814 cmi->set_active (visible);
816 /* one channel only */
822 /** Add a submenu with 1 item per channel for a controller on many channels. */
824 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
826 const std::string& name)
828 using namespace Menu_Helpers;
830 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
832 Menu* chn_menu = manage (new Menu);
833 MenuList& chn_items (chn_menu->items());
835 /* add a couple of items to hide/show this controller on all channels */
837 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
838 chn_items.push_back (
839 MenuElem (_("Hide all channels"),
840 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
841 false, param_without_channel)));
842 chn_items.push_back (
843 MenuElem (_("Show all channels"),
844 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
845 true, param_without_channel)));
847 for (uint8_t chn = 0; chn < 16; chn++) {
848 if (selected_channels & (0x0001 << chn)) {
850 /* for each selected channel, add a menu item for this controller */
852 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
853 chn_items.push_back (
854 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
855 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
856 fully_qualified_param)));
858 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
859 fully_qualified_param);
860 bool visible = false;
863 if (track->marked_for_display()) {
868 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
869 _controller_menu_map[fully_qualified_param] = cmi;
870 cmi->set_active (visible);
874 /* add the per-channel menu to the list of controllers, with the name of the controller */
875 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
877 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
880 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
881 MidiTimeAxisView::get_device_mode()
883 using namespace MIDI::Name;
885 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
887 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
890 return device_names->custom_device_mode_by_name(
891 gui_property (X_("midnam-custom-device-mode")));
894 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
895 MidiTimeAxisView::get_device_names()
897 using namespace MIDI::Name;
899 const std::string model = gui_property (X_("midnam-model-name"));
901 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
902 .document_by_model(model);
904 return midnam->master_device_names(model);
906 return boost::shared_ptr<MasterDeviceNames>();
911 MidiTimeAxisView::build_controller_menu ()
913 using namespace Menu_Helpers;
915 if (controller_menu) {
916 /* it exists and has not been invalidated by a channel mode change */
920 controller_menu = new Menu; // explicitly managed by us
921 MenuList& items (controller_menu->items());
923 /* create several "top level" menu items for sets of controllers (16 at a
924 time), and populate each one with a submenu for each controller+channel
925 combination covering the currently selected channels for this track
928 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
930 /* count the number of selected channels because we will build a different menu
931 structure if there is more than 1 selected.
935 for (uint8_t chn = 0; chn < 16; chn++) {
936 if (selected_channels & (0x0001 << chn)) {
943 using namespace MIDI::Name;
944 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
946 if (device_names && !device_names->controls().empty()) {
947 /* Controllers names available in midnam file, generate fancy menu */
948 unsigned n_items = 0;
949 unsigned n_groups = 0;
951 /* TODO: This is not correct, should look up the currently applicable ControlNameList
952 and only build a menu for that one. */
953 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
954 l != device_names->controls().end(); ++l) {
955 boost::shared_ptr<ControlNameList> name_list = l->second;
956 Menu* ctl_menu = NULL;
958 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
959 c != name_list->controls().end();) {
960 const uint16_t ctl = c->second->number();
961 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
962 /* Skip bank select controllers since they're handled specially */
964 /* Create a new submenu */
965 ctl_menu = manage (new Menu);
968 MenuList& ctl_items (ctl_menu->items());
970 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
972 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
977 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
978 /* Submenu has 16 items or we're done, add it to controller menu and reset */
980 MenuElem(string_compose(_("Controllers %1-%2"),
981 (16 * n_groups), (16 * n_groups) + n_items - 1),
990 /* No controllers names, generate generic numeric menu */
991 for (int i = 0; i < 127; i += 16) {
992 Menu* ctl_menu = manage (new Menu);
993 MenuList& ctl_items (ctl_menu->items());
995 for (int ctl = i; ctl < i+16; ++ctl) {
996 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
997 /* Skip bank select controllers since they're handled specially */
1002 add_multi_channel_controller_item(
1003 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1005 add_single_channel_controller_item(
1006 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1010 /* Add submenu for this block of controllers to controller menu */
1012 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1019 MidiTimeAxisView::build_note_mode_menu()
1021 using namespace Menu_Helpers;
1023 Menu* mode_menu = manage (new Menu);
1024 MenuList& items = mode_menu->items();
1025 mode_menu->set_name ("ArdourContextMenu");
1027 RadioMenuItem::Group mode_group;
1029 RadioMenuElem (mode_group,_("Sustained"),
1030 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1032 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1033 _note_mode_item->set_active(_note_mode == Sustained);
1036 RadioMenuElem (mode_group, _("Percussive"),
1037 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1038 Percussive, true)));
1039 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1040 _percussion_mode_item->set_active(_note_mode == Percussive);
1046 MidiTimeAxisView::build_color_mode_menu()
1048 using namespace Menu_Helpers;
1050 Menu* mode_menu = manage (new Menu);
1051 MenuList& items = mode_menu->items();
1052 mode_menu->set_name ("ArdourContextMenu");
1054 RadioMenuItem::Group mode_group;
1056 RadioMenuElem (mode_group, _("Meter Colors"),
1057 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1058 MeterColors, false, true, true)));
1059 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1060 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1063 RadioMenuElem (mode_group, _("Channel Colors"),
1064 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1065 ChannelColors, false, true, true)));
1066 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1067 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1070 RadioMenuElem (mode_group, _("Track Color"),
1071 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1072 TrackColor, false, true, true)));
1073 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1074 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1080 MidiTimeAxisView::build_patch_menu()
1082 using namespace MIDI::Name;
1083 using namespace Menu_Helpers;
1085 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1086 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1088 Menu* pc_menu = manage (new Menu);
1089 MenuList& pc_items = pc_menu->items();
1091 for (uint32_t chn = 0; chn < 16; ++chn) {
1092 boost::shared_ptr<ChannelNameSet> channel_name_set = device_names->channel_name_set_by_channel (device_mode, chn);
1093 // see also PatchChange::initialize_popup_menus
1094 if (!channel_name_set) {
1097 const ChannelNameSet::PatchBanks& patch_banks = channel_name_set->patch_banks();
1098 if (patch_banks.size () == 0) {
1102 Gtk::Menu& chan_menu = *manage(new Gtk::Menu());
1104 if (patch_banks.size() > 1) {
1106 for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin();
1107 bank != patch_banks.end();
1109 Glib::RefPtr<Glib::Regex> underscores = Glib::Regex::create("_");
1110 std::string replacement(" ");
1112 Gtk::Menu& patch_bank_menu = *manage(new Gtk::Menu());
1114 const PatchNameList& patches = (*bank)->patch_name_list();
1115 Gtk::Menu::MenuList& patch_menus = patch_bank_menu.items();
1117 for (PatchNameList::const_iterator patch = patches.begin();
1118 patch != patches.end();
1120 std::string name = underscores->replace((*patch)->name().c_str(), -1, 0, replacement);
1122 patch_menus.push_back(
1123 Gtk::Menu_Helpers::MenuElem(
1126 sigc::mem_fun(*this, &MidiTimeAxisView::on_patch_menu_selected),
1127 chn, (*patch)->patch_primary_key())) );
1131 std::string name = underscores->replace((*bank)->name().c_str(), -1, 0, replacement);
1133 chan_menu.items().push_back(
1134 Gtk::Menu_Helpers::MenuElem(
1139 /* only one patch bank, so make it the initial menu */
1141 const PatchNameList& patches = patch_banks.front()->patch_name_list();
1143 for (PatchNameList::const_iterator patch = patches.begin();
1144 patch != patches.end();
1146 std::string name = (*patch)->name();
1147 boost::replace_all (name, "_", " ");
1149 chan_menu.items().push_back (
1150 Gtk::Menu_Helpers::MenuElem (
1152 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::on_patch_menu_selected),
1153 chn, (*patch)->patch_primary_key())));
1158 Gtk::Menu_Helpers::MenuElem(
1159 string_compose (_("Channel %1"), chn + 1),
1166 MidiTimeAxisView::on_patch_menu_selected (int chn, const MIDI::Name::PatchPrimaryKey& key)
1171 boost::shared_ptr<AutomationControl> bank_msb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_MSB_BANK), true);
1172 boost::shared_ptr<AutomationControl> bank_lsb = _route->automation_control(Evoral::Parameter (MidiCCAutomation, chn, MIDI_CTL_LSB_BANK), true);
1173 boost::shared_ptr<AutomationControl> program = _route->automation_control(Evoral::Parameter (MidiPgmChangeAutomation, chn), true);
1175 if (!bank_msb || ! bank_lsb || !program) {
1178 bank_msb->set_value ((key.bank() >> 7) & 0x7f, Controllable::NoGroup);
1179 bank_lsb->set_value (key.bank() & 0x7f, Controllable::NoGroup);
1180 program->set_value (key.program(), Controllable::NoGroup);
1184 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1186 if (apply_to_selection) {
1187 _editor.get_selection().tracks.foreach_midi_time_axis (
1188 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1190 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1192 midi_track()->set_note_mode(mode);
1193 set_gui_property ("note-mode", enum_2_string(_note_mode));
1194 _view->redisplay_track();
1200 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1202 if (apply_to_selection) {
1203 _editor.get_selection().tracks.foreach_midi_time_axis (
1204 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1206 if (_color_mode == mode && !force) {
1210 if (_channel_selector) {
1211 if (mode == ChannelColors) {
1212 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1214 _channel_selector->set_default_channel_color();
1219 set_gui_property ("color-mode", enum_2_string(_color_mode));
1221 _view->redisplay_track();
1227 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1229 if (apply_to_selection) {
1230 _editor.get_selection().tracks.foreach_midi_time_axis (
1231 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1233 if (!_ignore_signals) {
1234 midi_view()->set_note_range(range);
1240 MidiTimeAxisView::update_range()
1245 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1247 using namespace MIDI::Name;
1249 if (apply_to_selection) {
1250 _editor.get_selection().tracks.foreach_midi_time_axis (
1251 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1254 // Show existing automation
1255 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1257 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1258 create_automation_child(*i, true);
1261 // Show automation for all controllers named in midnam file
1262 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1263 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1264 device_names && !device_names->controls().empty()) {
1265 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1266 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1267 for (uint32_t chn = 0; chn < 16; ++chn) {
1268 if ((selected_channels & (0x0001 << chn)) == 0) {
1269 // Channel not in use
1273 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1279 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1280 chan_names->control_list_name());
1281 if (!control_names) {
1285 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1286 c != control_names->controls().end();
1288 const uint16_t ctl = c->second->number();
1289 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1290 /* Skip bank select controllers since they're handled specially */
1291 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1292 create_automation_child(param, true);
1299 RouteTimeAxisView::show_all_automation ();
1304 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1306 if (apply_to_selection) {
1307 _editor.get_selection().tracks.foreach_midi_time_axis (
1308 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1311 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1313 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1314 create_automation_child (*i, true);
1318 RouteTimeAxisView::show_existing_automation ();
1322 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1325 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1327 if (param.type() == NullAutomation) {
1331 AutomationTracks::iterator existing = _automation_tracks.find (param);
1333 if (existing != _automation_tracks.end()) {
1335 /* automation track created because we had existing data for
1336 * the processor, but visibility may need to be controlled
1337 * since it will have been set visible by default.
1340 existing->second->set_marked_for_display (show);
1349 boost::shared_ptr<AutomationTimeAxisView> track;
1350 boost::shared_ptr<AutomationControl> control;
1353 switch (param.type()) {
1355 case GainAutomation:
1356 create_gain_automation_child (param, show);
1359 case MuteAutomation:
1360 create_mute_automation_child (param, show);
1363 case PluginAutomation:
1364 /* handled elsewhere */
1367 case MidiCCAutomation:
1368 case MidiPgmChangeAutomation:
1369 case MidiPitchBenderAutomation:
1370 case MidiChannelPressureAutomation:
1371 case MidiSystemExclusiveAutomation:
1372 /* These controllers are region "automation" - they are owned
1373 * by regions (and their MidiModels), not by the track. As a
1374 * result there is no AutomationList/Line for the track, but we create
1375 * a controller for the user to write immediate events, so the editor
1376 * can act as a control surface for the present MIDI controllers.
1378 * TODO: Record manipulation of the controller to regions?
1381 control = _route->automation_control(param, true);
1382 track.reset (new AutomationTimeAxisView (
1385 control ? _route : boost::shared_ptr<Automatable> (),
1392 _route->describe_parameter(param)));
1395 _view->foreach_regionview (
1396 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1399 add_automation_child (param, track, show);
1402 case PanWidthAutomation:
1403 case PanElevationAutomation:
1404 case PanAzimuthAutomation:
1405 ensure_pan_views (show);
1409 error << "MidiTimeAxisView: unknown automation child "
1410 << EventTypeMap::instance().to_symbol(param) << endmsg;
1415 MidiTimeAxisView::route_active_changed ()
1417 RouteUI::route_active_changed ();
1418 update_control_names();
1422 MidiTimeAxisView::update_control_names ()
1425 if (_route->active()) {
1426 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1427 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1429 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1430 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1432 } else { // MIDI bus (which doesn't exist yet..)
1433 if (_route->active()) {
1434 controls_base_selected_name = "BusControlsBaseSelected";
1435 controls_base_unselected_name = "BusControlsBaseUnselected";
1437 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1438 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1443 controls_ebox.set_name (controls_base_selected_name);
1444 time_axis_frame.set_name (controls_base_selected_name);
1446 controls_ebox.set_name (controls_base_unselected_name);
1447 time_axis_frame.set_name (controls_base_unselected_name);
1452 MidiTimeAxisView::set_note_selection (uint8_t note)
1454 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1456 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1458 if (_view->num_selected_regionviews() == 0) {
1459 _view->foreach_regionview (
1460 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1463 _view->foreach_selected_regionview (
1464 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1468 _editor.commit_reversible_selection_op();
1472 MidiTimeAxisView::add_note_selection (uint8_t note)
1474 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1476 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1478 if (_view->num_selected_regionviews() == 0) {
1479 _view->foreach_regionview (
1480 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1483 _view->foreach_selected_regionview (
1484 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1488 _editor.commit_reversible_selection_op();
1492 MidiTimeAxisView::extend_note_selection (uint8_t note)
1494 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1496 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1498 if (_view->num_selected_regionviews() == 0) {
1499 _view->foreach_regionview (
1500 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1503 _view->foreach_selected_regionview (
1504 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1508 _editor.commit_reversible_selection_op();
1512 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1514 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1516 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1518 if (_view->num_selected_regionviews() == 0) {
1519 _view->foreach_regionview (
1520 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1523 _view->foreach_selected_regionview (
1524 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1528 _editor.commit_reversible_selection_op();
1532 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1534 _view->foreach_regionview (
1535 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1539 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1541 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1545 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1547 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1551 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1553 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1557 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1559 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1563 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1565 Evoral::Sequence<Evoral::Beats>::Notes selected;
1566 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1568 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1570 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1571 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1572 notes.insert (*sel_it);
1575 if (!notes.empty()) {
1576 selection.push_back (make_pair ((rv)->region()->id(), notes));
1581 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1583 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1587 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1588 bool changed = false;
1592 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1594 for (uint32_t chn = 0; chn < 16; ++chn) {
1595 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1596 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1602 if ((selected_channels & (0x0001 << chn)) == 0) {
1603 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1604 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1606 changed = track->set_marked_for_display (false) || changed;
1608 changed = track->set_marked_for_display (true) || changed;
1615 /* TODO: Bender, Pressure */
1617 /* invalidate the controller menu, so that we rebuild it next time */
1618 _controller_menu_map.clear ();
1619 delete controller_menu;
1620 controller_menu = 0;
1628 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1630 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1635 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1636 if (i != _controller_menu_map.end()) {
1640 i = _channel_command_menu_map.find (param);
1641 if (i != _channel_command_menu_map.end()) {
1648 boost::shared_ptr<MidiRegion>
1649 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1651 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1652 MusicFrame pos (f, 0);
1655 real_editor->begin_reversible_command (Operations::create_region);
1657 playlist()->clear_changes ();
1659 real_editor->snap_to (pos, RoundNearest);
1661 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1664 plist.add (ARDOUR::Properties::start, 0);
1665 plist.add (ARDOUR::Properties::length, length);
1666 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1668 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1669 /* sets beat position */
1670 region->set_position (pos.frame, pos.division);
1671 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1672 _session->add_command (new StatefulDiffCommand (playlist()));
1675 real_editor->commit_reversible_command ();
1678 return boost::dynamic_pointer_cast<MidiRegion>(region);
1682 MidiTimeAxisView::ensure_step_editor ()
1684 if (!_step_editor) {
1685 _step_editor = new StepEditor (_editor, midi_track(), *this);
1690 MidiTimeAxisView::start_step_editing ()
1692 ensure_step_editor ();
1693 _step_editor->start_step_editing ();
1697 MidiTimeAxisView::stop_step_editing ()
1700 _step_editor->stop_step_editing ();
1704 /** @return channel (counted from 0) to add an event to, based on the current setting
1705 * of the channel selector.
1708 MidiTimeAxisView::get_channel_for_add () const
1710 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1712 uint8_t channel = 0;
1714 /* pick the highest selected channel, unless all channels are selected,
1715 which is interpreted to mean channel 1 (zero)
1718 for (uint16_t i = 0; i < 16; ++i) {
1719 if (chn_mask & (1<<i)) {
1725 if (chn_cnt == 16) {
1733 MidiTimeAxisView::note_range_changed ()
1735 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1736 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1740 MidiTimeAxisView::contents_height_changed ()
1742 _range_scroomer->queue_resize ();
1746 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1748 if (!_editor.internal_editing()) {
1749 // Non-internal paste, paste regions like any other route
1750 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1753 return midi_view()->paste(pos, selection, ctx, sub_num);