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 midi_view()->NoteRangeChanged.connect (
167 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
168 _view->ContentsHeightChanged.connect (
169 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
171 ignore_toggle = false;
173 if (is_midi_track()) {
174 _note_mode = midi_track()->note_mode();
177 /* if set_state above didn't create a gain automation child, we need to make one */
178 if (automation_child (GainAutomation) == 0) {
179 create_automation_child (GainAutomation, false);
182 /* if set_state above didn't create a mute automation child, we need to make one */
183 if (automation_child (MuteAutomation) == 0) {
184 create_automation_child (MuteAutomation, false);
187 if (_route->panner_shell()) {
188 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
191 /* map current state of the route */
192 ensure_pan_views (false);
193 update_control_names();
194 processors_changed (RouteProcessorChange ());
196 _route->processors_changed.connect (*this, invalidator (*this),
197 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
201 _piano_roll_header->SetNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
203 _piano_roll_header->AddNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
205 _piano_roll_header->ExtendNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
207 _piano_roll_header->ToggleNoteSelection.connect (
208 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
210 /* Suspend updates of the StreamView during scroomer drags to speed things up */
211 _range_scroomer->DragStarting.connect (
212 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
213 _range_scroomer->DragFinishing.connect (
214 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
216 /* Put the scroomer and the keyboard in a VBox with a padding
217 label so that they can be reduced in height for stacked-view
221 HSeparator* separator = manage (new HSeparator());
222 separator->set_name("TrackSeparator");
223 separator->set_size_request(-1, 1);
226 VBox* v = manage (new VBox);
227 HBox* h = manage (new HBox);
228 h->pack_end (*_piano_roll_header);
229 h->pack_end (*_range_scroomer);
230 v->pack_start (*separator, false, false);
231 v->pack_start (*h, true, true);
234 top_hbox.remove(scroomer_placeholder);
235 time_axis_hbox.pack_end(*v, false, false, 0);
236 midi_scroomer_size_group->add_widget (*v);
238 midi_view()->NoteRangeChanged.connect (
239 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
241 /* ask for notifications of any new RegionViews */
242 _view->RegionViewAdded.connect (
243 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
245 midi_track()->playback_filter().ChannelModeChanged.connect (
246 *this, invalidator (*this),
247 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
249 midi_track()->playback_filter().ChannelMaskChanged.connect (
250 *this, invalidator (*this),
251 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
253 midi_track()->capture_filter().ChannelModeChanged.connect (
254 *this, invalidator (*this),
255 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
257 midi_track()->capture_filter().ChannelMaskChanged.connect (
258 *this, invalidator (*this),
259 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
262 playback_channel_mode_changed ();
263 capture_channel_mode_changed ();
265 if (!_editor.have_idled()) {
266 /* first idle will do what we need */
272 if (gui_property (X_("midnam-model-name")).empty()) {
273 set_gui_property (X_("midnam-model-name"), "Generic");
276 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
277 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
279 set_gui_property (X_("midnam-custom-device-mode"),
280 *device_names->custom_device_mode_names().begin());
284 set_tooltip (_midnam_model_selector, _("External MIDI Device"));
285 set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
287 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
288 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
290 _midi_controls_box.set_homogeneous(false);
291 _midi_controls_box.set_border_width (2);
293 _channel_status_box.set_homogeneous (false);
294 _channel_status_box.set_spacing (4);
296 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
297 channel_selector_button->set_name ("route button");
298 set_tooltip (channel_selector_button, _("Click to edit channel settings"));
300 // Insert expanding space labels to get full width justification
301 _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
302 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
303 _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
304 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
305 _channel_status_box.pack_end (*channel_selector_button, false, false);
306 _channel_status_box.show_all ();
308 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
310 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
312 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
313 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
316 setup_midnam_patches ();
317 update_patch_selector ();
319 model_changed (gui_property(X_("midnam-model-name")));
320 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
322 controls_vbox.pack_start(_midi_controls_box, false, false);
324 const string color_mode = gui_property ("color-mode");
325 if (!color_mode.empty()) {
326 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
327 if (_channel_selector && _color_mode == ChannelColors) {
328 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
332 set_color_mode (_color_mode, true, false);
334 const string note_mode = gui_property ("note-mode");
335 if (!note_mode.empty()) {
336 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
337 if (_percussion_mode_item) {
338 _percussion_mode_item->set_active (_note_mode == Percussive);
342 /* Look for any GUI object state nodes that represent automation children
343 * that should exist, and create the children.
346 const list<string> gui_ids = gui_object_state().all_ids ();
347 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
350 Evoral::Parameter parameter (0, 0, 0);
352 bool const p = AutomationTimeAxisView::parse_state_id (
353 *i, route_id, has_parameter, parameter);
354 if (p && route_id == _route->id () && has_parameter) {
355 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
356 create_automation_child (parameter, string_is_affirmative (visible));
362 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
364 RouteTimeAxisView::processors_changed (c);
365 update_patch_selector ();
369 MidiTimeAxisView::first_idle ()
376 MidiTimeAxisView::~MidiTimeAxisView ()
378 delete _channel_selector;
380 delete _piano_roll_header;
381 _piano_roll_header = 0;
383 delete _range_scroomer;
386 delete controller_menu;
391 MidiTimeAxisView::check_step_edit ()
393 ensure_step_editor ();
394 _step_editor->check_step_edit ();
398 MidiTimeAxisView::setup_midnam_patches ()
400 typedef MIDI::Name::MidiPatchManager PatchManager;
401 PatchManager& patch_manager = PatchManager::instance();
403 _midnam_model_selector.clear_items ();
404 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
405 m != patch_manager.devices_by_manufacturer().end(); ++m) {
406 Menu* menu = Gtk::manage(new Menu);
407 Menu_Helpers::MenuList& items = menu->items();
409 // Build manufacturer submenu
410 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
411 n != m->second.end(); ++n) {
412 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
414 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
417 items.push_back(elem);
420 // Add manufacturer submenu to selector
421 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
424 if (!get_device_names()) {
425 model_changed ("Generic");
430 MidiTimeAxisView::drop_instrument_ref ()
432 midnam_connection.drop_connections ();
436 MidiTimeAxisView::update_patch_selector ()
438 typedef MIDI::Name::MidiPatchManager PatchManager;
439 PatchManager& patch_manager = PatchManager::instance();
441 bool pluginprovided = false;
443 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
444 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
445 if (pi && pi->plugin ()->has_midnam ()) {
446 midnam_connection.drop_connections ();
447 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
448 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
450 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
451 boost::bind (&Plugin::read_midnam, pi->plugin ()),
454 pluginprovided = true;
455 std::string model_name = pi->plugin ()->midnam_model ();
456 if (gui_property (X_("midnam-model-name")) != model_name) {
457 model_changed (model_name);
462 if (patch_manager.all_models().empty() || pluginprovided) {
463 _midnam_model_selector.hide ();
464 _midnam_custom_device_mode_selector.hide ();
466 _midnam_model_selector.show ();
467 _midnam_custom_device_mode_selector.show ();
472 MidiTimeAxisView::model_changed(const std::string& model)
474 set_gui_property (X_("midnam-model-name"), model);
476 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
477 .custom_device_mode_names_by_model(model);
479 _midnam_model_selector.set_text(model);
480 _midnam_custom_device_mode_selector.clear_items();
482 for (std::list<std::string>::const_iterator i = device_modes.begin();
483 i != device_modes.end(); ++i) {
484 _midnam_custom_device_mode_selector.AddMenuElem(
485 Gtk::Menu_Helpers::MenuElem(
486 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
490 if (!device_modes.empty()) {
491 custom_device_mode_changed(device_modes.front());
494 if (device_modes.size() > 1) {
495 _midnam_custom_device_mode_selector.show();
497 _midnam_custom_device_mode_selector.hide();
500 // now this is a real bad hack
501 if (device_modes.size() > 0) {
502 _route->instrument_info().set_external_instrument (model, device_modes.front());
504 _route->instrument_info().set_external_instrument (model, "");
507 // Rebuild controller menu
508 _controller_menu_map.clear ();
509 delete controller_menu;
511 build_automation_action_menu(false);
515 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
517 const std::string model = gui_property (X_("midnam-model-name"));
519 set_gui_property (X_("midnam-custom-device-mode"), mode);
520 _midnam_custom_device_mode_selector.set_text(mode);
521 _route->instrument_info().set_external_instrument (model, mode);
525 MidiTimeAxisView::midi_view()
527 return dynamic_cast<MidiStreamView*>(_view);
531 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
533 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
534 _midi_controls_box.show ();
536 _midi_controls_box.hide();
539 if (h >= KEYBOARD_MIN_HEIGHT) {
540 if (is_track() && _range_scroomer) {
541 _range_scroomer->show();
543 if (is_track() && _piano_roll_header) {
544 _piano_roll_header->show();
547 if (is_track() && _range_scroomer) {
548 _range_scroomer->hide();
550 if (is_track() && _piano_roll_header) {
551 _piano_roll_header->hide();
555 /* We need to do this after changing visibility of our stuff, as it will
556 eventually trigger a call to Editor::reset_controls_layout_width(),
557 which needs to know if we have just shown or hidden a scroomer /
560 RouteTimeAxisView::set_height (h, m);
564 MidiTimeAxisView::append_extra_display_menu_items ()
566 using namespace Menu_Helpers;
568 MenuList& items = display_menu->items();
571 Menu *range_menu = manage(new Menu);
572 MenuList& range_items = range_menu->items();
573 range_menu->set_name ("ArdourContextMenu");
575 range_items.push_back (
576 MenuElem (_("Show Full Range"),
577 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
578 MidiStreamView::FullRange, true)));
580 range_items.push_back (
581 MenuElem (_("Fit Contents"),
582 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
583 MidiStreamView::ContentsRange, true)));
585 items.push_back (MenuElem (_("Note Range"), *range_menu));
586 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
587 items.push_back (MenuElem (_("Channel Selector"),
588 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
590 color_mode_menu = build_color_mode_menu();
591 if (color_mode_menu) {
592 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
595 items.push_back (SeparatorElem ());
599 MidiTimeAxisView::toggle_channel_selector ()
601 if (!_channel_selector) {
602 _channel_selector = new MidiChannelSelectorWindow (midi_track());
604 if (_color_mode == ChannelColors) {
605 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
607 _channel_selector->set_default_channel_color ();
610 _channel_selector->show_all ();
612 _channel_selector->cycle_visibility ();
617 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
619 using namespace Menu_Helpers;
621 /* If we have a controller menu, we need to detach it before
622 RouteTimeAxis::build_automation_action_menu destroys the
623 menu it is attached to. Otherwise GTK destroys
624 controller_menu's gobj, meaning that it can't be reattached
625 below. See bug #3134.
628 if (controller_menu) {
629 detach_menu (*controller_menu);
632 _channel_command_menu_map.clear ();
633 RouteTimeAxisView::build_automation_action_menu (for_selection);
635 MenuList& automation_items = automation_action_menu->items();
637 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
639 if (selected_channels != 0) {
641 automation_items.push_back (SeparatorElem());
643 /* these 2 MIDI "command" types are semantically more like automation
644 than note data, but they are not MIDI controllers. We give them
645 special status in this menu, since they will not show up in the
646 controller list and anyone who actually knows something about MIDI
647 (!) would not expect to find them there.
650 add_channel_command_menu_item (
651 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
652 automation_items.back().set_sensitive (
653 !for_selection || _editor.get_selection().tracks.size() == 1);
654 add_channel_command_menu_item (
655 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
656 automation_items.back().set_sensitive (
657 !for_selection || _editor.get_selection().tracks.size() == 1);
659 /* now all MIDI controllers. Always offer the possibility that we will
660 rebuild the controllers menu since it might need to be updated after
661 a channel mode change or other change. Also detach it first in case
662 it has been used anywhere else.
665 build_controller_menu ();
667 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
669 if (!poly_pressure_menu) {
670 poly_pressure_menu = new Gtk::Menu;
673 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
675 automation_items.back().set_sensitive (
676 !for_selection || _editor.get_selection().tracks.size() == 1);
678 automation_items.push_back (
679 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
680 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
685 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
687 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
689 for (uint8_t chn = 0; chn < 16; chn++) {
690 if (selected_channels & (0x0001 << chn)) {
692 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
693 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
696 menu->set_active (yn);
703 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
705 AutomationType auto_type,
708 using namespace Menu_Helpers;
710 /* count the number of selected channels because we will build a different menu
711 structure if there is more than 1 selected.
714 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
717 for (uint8_t chn = 0; chn < 16; chn++) {
718 if (selected_channels & (0x0001 << chn)) {
727 /* multiple channels - create a submenu, with 1 item per channel */
729 Menu* chn_menu = manage (new Menu);
730 MenuList& chn_items (chn_menu->items());
731 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
733 /* add a couple of items to hide/show all of them */
735 chn_items.push_back (
736 MenuElem (_("Hide all channels"),
737 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
738 false, param_without_channel)));
739 chn_items.push_back (
740 MenuElem (_("Show all channels"),
741 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
742 true, param_without_channel)));
744 for (uint8_t chn = 0; chn < 16; chn++) {
745 if (selected_channels & (0x0001 << chn)) {
747 /* for each selected channel, add a menu item for this controller */
749 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
750 chn_items.push_back (
751 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
752 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
753 fully_qualified_param)));
755 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
756 bool visible = false;
759 if (track->marked_for_display()) {
764 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
765 _channel_command_menu_map[fully_qualified_param] = cmi;
766 cmi->set_active (visible);
770 /* now create an item in the parent menu that has the per-channel list as a submenu */
772 items.push_back (MenuElem (label, *chn_menu));
776 /* just one channel - create a single menu item for this command+channel combination*/
778 for (uint8_t chn = 0; chn < 16; chn++) {
779 if (selected_channels & (0x0001 << chn)) {
781 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
783 CheckMenuElem (label,
784 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
785 fully_qualified_param)));
787 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
788 bool visible = false;
791 if (track->marked_for_display()) {
796 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
797 _channel_command_menu_map[fully_qualified_param] = cmi;
798 cmi->set_active (visible);
800 /* one channel only */
807 /** Add a single menu item for a controller on one channel. */
809 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
811 const std::string& name)
813 using namespace Menu_Helpers;
815 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
816 for (uint8_t chn = 0; chn < 16; chn++) {
817 if (selected_channels & (0x0001 << chn)) {
819 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
820 ctl_items.push_back (
822 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
824 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
825 fully_qualified_param)));
826 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
828 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
829 fully_qualified_param);
831 bool visible = false;
833 if (track->marked_for_display()) {
838 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
839 _controller_menu_map[fully_qualified_param] = cmi;
840 cmi->set_active (visible);
842 /* one channel only */
848 /** Add a submenu with 1 item per channel for a controller on many channels. */
850 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
852 const std::string& name)
854 using namespace Menu_Helpers;
856 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
858 Menu* chn_menu = manage (new Menu);
859 MenuList& chn_items (chn_menu->items());
861 /* add a couple of items to hide/show this controller on all channels */
863 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
864 chn_items.push_back (
865 MenuElem (_("Hide all channels"),
866 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
867 false, param_without_channel)));
868 chn_items.push_back (
869 MenuElem (_("Show all channels"),
870 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
871 true, param_without_channel)));
873 for (uint8_t chn = 0; chn < 16; chn++) {
874 if (selected_channels & (0x0001 << chn)) {
876 /* for each selected channel, add a menu item for this controller */
878 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
879 chn_items.push_back (
880 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
881 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
882 fully_qualified_param)));
884 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
885 fully_qualified_param);
886 bool visible = false;
889 if (track->marked_for_display()) {
894 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
895 _controller_menu_map[fully_qualified_param] = cmi;
896 cmi->set_active (visible);
900 /* add the per-channel menu to the list of controllers, with the name of the controller */
901 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
903 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
906 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
907 MidiTimeAxisView::get_device_mode()
909 using namespace MIDI::Name;
911 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
913 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
916 return device_names->custom_device_mode_by_name(
917 gui_property (X_("midnam-custom-device-mode")));
920 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
921 MidiTimeAxisView::get_device_names()
923 using namespace MIDI::Name;
925 const std::string model = gui_property (X_("midnam-model-name"));
927 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
928 .document_by_model(model);
930 return midnam->master_device_names(model);
932 return boost::shared_ptr<MasterDeviceNames>();
937 MidiTimeAxisView::build_controller_menu ()
939 using namespace Menu_Helpers;
941 if (controller_menu) {
942 /* it exists and has not been invalidated by a channel mode change */
946 controller_menu = new Menu; // explicitly managed by us
947 MenuList& items (controller_menu->items());
949 /* create several "top level" menu items for sets of controllers (16 at a
950 time), and populate each one with a submenu for each controller+channel
951 combination covering the currently selected channels for this track
954 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
956 /* count the number of selected channels because we will build a different menu
957 structure if there is more than 1 selected.
961 for (uint8_t chn = 0; chn < 16; chn++) {
962 if (selected_channels & (0x0001 << chn)) {
969 using namespace MIDI::Name;
970 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
972 if (device_names && !device_names->controls().empty()) {
973 /* Controllers names available in midnam file, generate fancy menu */
974 unsigned n_items = 0;
975 unsigned n_groups = 0;
977 /* TODO: This is not correct, should look up the currently applicable ControlNameList
978 and only build a menu for that one. */
979 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
980 l != device_names->controls().end(); ++l) {
981 boost::shared_ptr<ControlNameList> name_list = l->second;
982 Menu* ctl_menu = NULL;
984 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
985 c != name_list->controls().end();) {
986 const uint16_t ctl = c->second->number();
987 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
988 /* Skip bank select controllers since they're handled specially */
990 /* Create a new submenu */
991 ctl_menu = manage (new Menu);
994 MenuList& ctl_items (ctl_menu->items());
996 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
998 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
1003 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
1004 /* Submenu has 16 items or we're done, add it to controller menu and reset */
1006 MenuElem(string_compose(_("Controllers %1-%2"),
1007 (16 * n_groups), (16 * n_groups) + n_items - 1),
1016 /* No controllers names, generate generic numeric menu */
1017 for (int i = 0; i < 127; i += 16) {
1018 Menu* ctl_menu = manage (new Menu);
1019 MenuList& ctl_items (ctl_menu->items());
1021 for (int ctl = i; ctl < i+16; ++ctl) {
1022 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1023 /* Skip bank select controllers since they're handled specially */
1028 add_multi_channel_controller_item(
1029 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1031 add_single_channel_controller_item(
1032 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1036 /* Add submenu for this block of controllers to controller menu */
1038 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1045 MidiTimeAxisView::build_note_mode_menu()
1047 using namespace Menu_Helpers;
1049 Menu* mode_menu = manage (new Menu);
1050 MenuList& items = mode_menu->items();
1051 mode_menu->set_name ("ArdourContextMenu");
1053 RadioMenuItem::Group mode_group;
1055 RadioMenuElem (mode_group,_("Sustained"),
1056 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1058 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1059 _note_mode_item->set_active(_note_mode == Sustained);
1062 RadioMenuElem (mode_group, _("Percussive"),
1063 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1064 Percussive, true)));
1065 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1066 _percussion_mode_item->set_active(_note_mode == Percussive);
1072 MidiTimeAxisView::build_color_mode_menu()
1074 using namespace Menu_Helpers;
1076 Menu* mode_menu = manage (new Menu);
1077 MenuList& items = mode_menu->items();
1078 mode_menu->set_name ("ArdourContextMenu");
1080 RadioMenuItem::Group mode_group;
1082 RadioMenuElem (mode_group, _("Meter Colors"),
1083 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1084 MeterColors, false, true, true)));
1085 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1086 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1089 RadioMenuElem (mode_group, _("Channel Colors"),
1090 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1091 ChannelColors, false, true, true)));
1092 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1093 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1096 RadioMenuElem (mode_group, _("Track Color"),
1097 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1098 TrackColor, false, true, true)));
1099 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1100 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1106 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1108 if (apply_to_selection) {
1109 _editor.get_selection().tracks.foreach_midi_time_axis (
1110 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1112 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1114 midi_track()->set_note_mode(mode);
1115 set_gui_property ("note-mode", enum_2_string(_note_mode));
1116 _view->redisplay_track();
1122 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1124 if (apply_to_selection) {
1125 _editor.get_selection().tracks.foreach_midi_time_axis (
1126 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1128 if (_color_mode == mode && !force) {
1132 if (_channel_selector) {
1133 if (mode == ChannelColors) {
1134 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1136 _channel_selector->set_default_channel_color();
1141 set_gui_property ("color-mode", enum_2_string(_color_mode));
1143 _view->redisplay_track();
1149 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1151 if (apply_to_selection) {
1152 _editor.get_selection().tracks.foreach_midi_time_axis (
1153 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1155 if (!_ignore_signals) {
1156 midi_view()->set_note_range(range);
1162 MidiTimeAxisView::update_range()
1164 MidiGhostRegion* mgr;
1166 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1167 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1168 mgr->update_range();
1174 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1176 using namespace MIDI::Name;
1178 if (apply_to_selection) {
1179 _editor.get_selection().tracks.foreach_midi_time_axis (
1180 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1183 // Show existing automation
1184 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1186 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1187 create_automation_child(*i, true);
1190 // Show automation for all controllers named in midnam file
1191 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1192 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1193 device_names && !device_names->controls().empty()) {
1194 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1195 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1196 for (uint32_t chn = 0; chn < 16; ++chn) {
1197 if ((selected_channels & (0x0001 << chn)) == 0) {
1198 // Channel not in use
1202 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1208 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1209 chan_names->control_list_name());
1210 if (!control_names) {
1214 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1215 c != control_names->controls().end();
1217 const uint16_t ctl = c->second->number();
1218 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1219 /* Skip bank select controllers since they're handled specially */
1220 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1221 create_automation_child(param, true);
1228 RouteTimeAxisView::show_all_automation ();
1233 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1235 if (apply_to_selection) {
1236 _editor.get_selection().tracks.foreach_midi_time_axis (
1237 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1240 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1242 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1243 create_automation_child (*i, true);
1247 RouteTimeAxisView::show_existing_automation ();
1251 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1254 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1256 if (param.type() == NullAutomation) {
1260 AutomationTracks::iterator existing = _automation_tracks.find (param);
1262 if (existing != _automation_tracks.end()) {
1264 /* automation track created because we had existing data for
1265 * the processor, but visibility may need to be controlled
1266 * since it will have been set visible by default.
1269 existing->second->set_marked_for_display (show);
1278 boost::shared_ptr<AutomationTimeAxisView> track;
1279 boost::shared_ptr<AutomationControl> control;
1282 switch (param.type()) {
1284 case GainAutomation:
1285 create_gain_automation_child (param, show);
1288 case MuteAutomation:
1289 create_mute_automation_child (param, show);
1292 case PluginAutomation:
1293 /* handled elsewhere */
1296 case MidiCCAutomation:
1297 case MidiPgmChangeAutomation:
1298 case MidiPitchBenderAutomation:
1299 case MidiChannelPressureAutomation:
1300 case MidiSystemExclusiveAutomation:
1301 /* These controllers are region "automation" - they are owned
1302 * by regions (and their MidiModels), not by the track. As a
1303 * result there is no AutomationList/Line for the track, but we create
1304 * a controller for the user to write immediate events, so the editor
1305 * can act as a control surface for the present MIDI controllers.
1307 * TODO: Record manipulation of the controller to regions?
1310 control = _route->automation_control(param, true);
1311 track.reset (new AutomationTimeAxisView (
1314 control ? _route : boost::shared_ptr<Automatable> (),
1321 _route->describe_parameter(param)));
1324 _view->foreach_regionview (
1325 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1328 add_automation_child (param, track, show);
1331 case PanWidthAutomation:
1332 case PanElevationAutomation:
1333 case PanAzimuthAutomation:
1334 ensure_pan_views (show);
1338 error << "MidiTimeAxisView: unknown automation child "
1339 << EventTypeMap::instance().to_symbol(param) << endmsg;
1344 MidiTimeAxisView::route_active_changed ()
1346 RouteUI::route_active_changed ();
1347 update_control_names();
1351 MidiTimeAxisView::update_control_names ()
1354 if (_route->active()) {
1355 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1356 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1358 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1359 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1361 } else { // MIDI bus (which doesn't exist yet..)
1362 if (_route->active()) {
1363 controls_base_selected_name = "BusControlsBaseSelected";
1364 controls_base_unselected_name = "BusControlsBaseUnselected";
1366 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1367 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1372 controls_ebox.set_name (controls_base_selected_name);
1373 time_axis_frame.set_name (controls_base_selected_name);
1375 controls_ebox.set_name (controls_base_unselected_name);
1376 time_axis_frame.set_name (controls_base_unselected_name);
1381 MidiTimeAxisView::set_note_selection (uint8_t note)
1383 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1385 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1387 if (_view->num_selected_regionviews() == 0) {
1388 _view->foreach_regionview (
1389 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1392 _view->foreach_selected_regionview (
1393 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1397 _editor.commit_reversible_selection_op();
1401 MidiTimeAxisView::add_note_selection (uint8_t note)
1403 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1405 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1407 if (_view->num_selected_regionviews() == 0) {
1408 _view->foreach_regionview (
1409 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1412 _view->foreach_selected_regionview (
1413 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1417 _editor.commit_reversible_selection_op();
1421 MidiTimeAxisView::extend_note_selection (uint8_t note)
1423 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1425 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1427 if (_view->num_selected_regionviews() == 0) {
1428 _view->foreach_regionview (
1429 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1432 _view->foreach_selected_regionview (
1433 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1437 _editor.commit_reversible_selection_op();
1441 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1443 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1445 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1447 if (_view->num_selected_regionviews() == 0) {
1448 _view->foreach_regionview (
1449 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1452 _view->foreach_selected_regionview (
1453 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1457 _editor.commit_reversible_selection_op();
1461 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1463 _view->foreach_regionview (
1464 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1468 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1470 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1474 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1476 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1480 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1482 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1486 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1488 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1492 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1494 Evoral::Sequence<Evoral::Beats>::Notes selected;
1495 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1497 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1499 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1500 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1501 notes.insert (*sel_it);
1504 if (!notes.empty()) {
1505 selection.push_back (make_pair ((rv)->region()->id(), notes));
1510 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1512 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1516 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1517 bool changed = false;
1521 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1523 for (uint32_t chn = 0; chn < 16; ++chn) {
1524 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1525 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1531 if ((selected_channels & (0x0001 << chn)) == 0) {
1532 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1533 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1535 changed = track->set_marked_for_display (false) || changed;
1537 changed = track->set_marked_for_display (true) || changed;
1544 /* TODO: Bender, Pressure */
1546 /* invalidate the controller menu, so that we rebuild it next time */
1547 _controller_menu_map.clear ();
1548 delete controller_menu;
1549 controller_menu = 0;
1557 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1559 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1564 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1565 if (i != _controller_menu_map.end()) {
1569 i = _channel_command_menu_map.find (param);
1570 if (i != _channel_command_menu_map.end()) {
1577 boost::shared_ptr<MidiRegion>
1578 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit, const int32_t sub_num)
1580 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1582 real_editor->begin_reversible_command (Operations::create_region);
1584 playlist()->clear_changes ();
1586 real_editor->snap_to (pos, RoundNearest);
1588 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1591 plist.add (ARDOUR::Properties::start, 0);
1592 plist.add (ARDOUR::Properties::length, length);
1593 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1595 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1596 /* sets beat position */
1597 region->set_position (pos, sub_num);
1598 playlist()->add_region (region, pos, 1.0, false, sub_num);
1599 _session->add_command (new StatefulDiffCommand (playlist()));
1602 real_editor->commit_reversible_command ();
1605 return boost::dynamic_pointer_cast<MidiRegion>(region);
1609 MidiTimeAxisView::ensure_step_editor ()
1611 if (!_step_editor) {
1612 _step_editor = new StepEditor (_editor, midi_track(), *this);
1617 MidiTimeAxisView::start_step_editing ()
1619 ensure_step_editor ();
1620 _step_editor->start_step_editing ();
1624 MidiTimeAxisView::stop_step_editing ()
1627 _step_editor->stop_step_editing ();
1631 /** @return channel (counted from 0) to add an event to, based on the current setting
1632 * of the channel selector.
1635 MidiTimeAxisView::get_channel_for_add () const
1637 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1639 uint8_t channel = 0;
1641 /* pick the highest selected channel, unless all channels are selected,
1642 which is interpreted to mean channel 1 (zero)
1645 for (uint16_t i = 0; i < 16; ++i) {
1646 if (chn_mask & (1<<i)) {
1652 if (chn_cnt == 16) {
1660 MidiTimeAxisView::note_range_changed ()
1662 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1663 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1667 MidiTimeAxisView::contents_height_changed ()
1669 _range_scroomer->queue_resize ();
1673 MidiTimeAxisView::playback_channel_mode_changed ()
1675 /* Invalidate the controller automation menu */
1676 delete controller_menu;
1677 controller_menu = 0;
1678 /* Update the button text */
1679 switch (midi_track()->get_playback_channel_mode()) {
1681 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1683 case FilterChannels:
1684 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1687 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1693 MidiTimeAxisView::capture_channel_mode_changed ()
1695 switch (midi_track()->get_capture_channel_mode()) {
1697 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1699 case FilterChannels:
1700 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1703 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1709 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1711 if (!_editor.internal_editing()) {
1712 // Non-internal paste, paste regions like any other route
1713 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1716 return midi_view()->paste(pos, selection, ctx, sub_num);