2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/profile.h"
54 #include "ardour/region.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_object.h"
59 #include "ardour/source.h"
60 #include "ardour/track.h"
61 #include "ardour/types.h"
63 #include "ardour_ui.h"
64 #include "ardour_button.h"
65 #include "automation_line.h"
66 #include "automation_time_axis.h"
69 #include "ghostregion.h"
70 #include "gui_thread.h"
72 #include "midi_channel_selector.h"
73 #include "midi_scroomer.h"
74 #include "midi_streamview.h"
75 #include "midi_region_view.h"
76 #include "midi_time_axis.h"
77 #include "piano_roll_header.h"
78 #include "playlist_selector.h"
79 #include "plugin_selector.h"
80 #include "plugin_ui.h"
81 #include "point_selection.h"
83 #include "region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "step_editor.h"
88 #include "note_base.h"
90 #include "ardour/midi_track.h"
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
101 // Minimum height at which a control is displayed
102 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
103 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
105 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
106 : AxisView(sess) // virtually inherited
107 , RouteTimeAxisView(ed, sess, canvas)
108 , _ignore_signals(false)
110 , _piano_roll_header(0)
111 , _note_mode(Sustained)
113 , _percussion_mode_item(0)
114 , _color_mode(MeterColors)
115 , _meter_color_mode_item(0)
116 , _channel_color_mode_item(0)
117 , _track_color_mode_item(0)
118 , _channel_selector (0)
119 , _step_edit_item (0)
120 , controller_menu (0)
126 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
130 _view = new MidiStreamView (*this);
133 _piano_roll_header = new PianoRollHeader(*midi_view());
134 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
135 _range_scroomer->DoubleClicked.connect (
136 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
137 MidiStreamView::ContentsRange, false));
140 /* This next call will result in our height being set up, so it must come after
141 the creation of the piano roll / range scroomer as their visibility is set up
144 RouteTimeAxisView::set_route (rt);
146 _view->apply_color (_color, StreamView::RegionColor);
148 subplugin_menu.set_name ("ArdourContextMenu");
150 if (!gui_property ("note-range-min").empty ()) {
151 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
152 atoi (gui_property ("note-range-max").c_str()),
156 midi_view()->NoteRangeChanged.connect (
157 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
158 _view->ContentsHeightChanged.connect (
159 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
161 ignore_toggle = false;
163 if (is_midi_track()) {
164 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
165 _note_mode = midi_track()->note_mode();
166 } else { // MIDI bus (which doesn't exist yet..)
167 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
170 /* if set_state above didn't create a gain automation child, we need to make one */
171 if (automation_child (GainAutomation) == 0) {
172 create_automation_child (GainAutomation, false);
175 /* if set_state above didn't create a mute automation child, we need to make one */
176 if (automation_child (MuteAutomation) == 0) {
177 create_automation_child (MuteAutomation, false);
180 if (_route->panner_shell()) {
181 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
184 /* map current state of the route */
185 ensure_pan_views (false);
187 processors_changed (RouteProcessorChange ());
189 _route->processors_changed.connect (*this, invalidator (*this),
190 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
194 _piano_roll_header->SetNoteSelection.connect (
195 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
196 _piano_roll_header->AddNoteSelection.connect (
197 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
198 _piano_roll_header->ExtendNoteSelection.connect (
199 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
200 _piano_roll_header->ToggleNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
203 /* Suspend updates of the StreamView during scroomer drags to speed things up */
204 _range_scroomer->DragStarting.connect (
205 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
206 _range_scroomer->DragFinishing.connect (
207 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
209 /* Put the scroomer and the keyboard in a VBox with a padding
210 label so that they can be reduced in height for stacked-view
214 top_hbox.remove(gm.get_level_meter());
215 VBox* v = manage (new VBox);
216 HBox* h = manage (new HBox);
217 h->pack_end (*_piano_roll_header);
218 h->pack_end (*_range_scroomer);
219 h->pack_end (gm.get_level_meter(), false, false, 4);
220 v->pack_start (*h, false, false);
223 top_hbox.pack_end(*v, false, false, 0);
224 if (!ARDOUR::Profile->get_mixbus()) {
225 controls_meters_size_group->remove_widget (gm.get_level_meter());
226 controls_meters_size_group->add_widget (*h);
228 // make up for level_meter 4 spc padding in RTA
229 Gtk::Fixed *blank = manage(new Gtk::Fixed());
230 blank->set_size_request(8, -1);
232 top_hbox.pack_end(*blank, false, false, 0);
234 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
235 controls_base_selected_name = "MidiTrackControlsBaseSelected";
236 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
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()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
246 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
248 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
249 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
251 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
252 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
254 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
255 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
258 playback_channel_mode_changed ();
259 capture_channel_mode_changed ();
261 if (!_editor.have_idled()) {
262 /* first idle will do what we need */
268 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
270 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
271 for (; m != patch_manager.all_models().end(); ++m) {
272 _midnam_model_selector.append_text(m->c_str());
275 if (gui_property (X_("midnam-model-name")).empty()) {
276 set_gui_property (X_("midnam-model-name"), "Generic");
279 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
280 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
282 set_gui_property (X_("midnam-custom-device-mode"),
283 *device_names->custom_device_mode_names().begin());
287 _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
288 _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
290 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
291 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
293 _midi_controls_box.set_homogeneous(false);
294 _midi_controls_box.set_border_width (10);
296 _channel_status_box.set_homogeneous (false);
297 _channel_status_box.set_spacing (6);
299 _channel_selector_button.set_label (_("Chns"));
300 ARDOUR_UI::instance()->set_tip (_channel_selector_button, _("Click to edit channel settings"));
302 /* fixed sized labels to prevent silly nonsense (though obviously,
303 * they cause their own too)
306 _playback_channel_status.set_size_request (65, -1);
307 _capture_channel_status.set_size_request (60, -1);
309 _channel_status_box.pack_start (_playback_channel_status, false, false);
310 _channel_status_box.pack_start (_capture_channel_status, false, false);
311 _channel_status_box.pack_start (_channel_selector_button, false, false);
312 _channel_status_box.show_all ();
314 _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
316 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
318 if (!patch_manager.all_models().empty()) {
320 _midnam_model_selector.set_size_request(22, 30);
321 _midnam_model_selector.set_border_width(2);
322 _midnam_model_selector.show ();
323 _midi_controls_box.pack_start (_midnam_model_selector);
325 _midnam_custom_device_mode_selector.set_size_request(10, 30);
326 _midnam_custom_device_mode_selector.set_border_width(2);
327 _midnam_custom_device_mode_selector.show ();
329 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
333 custom_device_mode_changed();
335 _midnam_model_selector.signal_changed().connect(
336 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
337 _midnam_custom_device_mode_selector.signal_changed().connect(
338 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
340 controls_vbox.pack_start(_midi_controls_box, false, false);
342 const string color_mode = gui_property ("color-mode");
343 if (!color_mode.empty()) {
344 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
345 if (_channel_selector && _color_mode == ChannelColors) {
346 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
350 set_color_mode (_color_mode, true, false);
352 const string note_mode = gui_property ("note-mode");
353 if (!note_mode.empty()) {
354 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
355 if (_percussion_mode_item) {
356 _percussion_mode_item->set_active (_note_mode == Percussive);
360 /* Look for any GUI object state nodes that represent automation children
361 * that should exist, and create the children.
364 const list<string> gui_ids = gui_object_state().all_ids ();
365 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
368 Evoral::Parameter parameter (0, 0, 0);
370 bool const p = AutomationTimeAxisView::parse_state_id (
371 *i, route_id, has_parameter, parameter);
372 if (p && route_id == _route->id () && has_parameter) {
373 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
374 create_automation_child (parameter, string_is_affirmative (visible));
380 MidiTimeAxisView::first_idle ()
387 MidiTimeAxisView::~MidiTimeAxisView ()
389 delete _channel_selector;
391 delete _piano_roll_header;
392 _piano_roll_header = 0;
394 delete _range_scroomer;
397 delete controller_menu;
402 MidiTimeAxisView::enter_internal_edit_mode ()
405 midi_view()->enter_internal_edit_mode ();
410 MidiTimeAxisView::leave_internal_edit_mode ()
413 midi_view()->leave_internal_edit_mode ();
418 MidiTimeAxisView::check_step_edit ()
420 ensure_step_editor ();
421 _step_editor->check_step_edit ();
425 MidiTimeAxisView::model_changed()
427 const Glib::ustring model = _midnam_model_selector.get_active_text();
428 set_gui_property (X_("midnam-model-name"), model);
430 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
431 .custom_device_mode_names_by_model(model);
433 _midnam_custom_device_mode_selector.clear_items();
435 for (std::list<std::string>::const_iterator i = device_modes.begin();
436 i != device_modes.end(); ++i) {
437 _midnam_custom_device_mode_selector.append_text(*i);
440 _midnam_custom_device_mode_selector.set_active(0);
442 _route->instrument_info().set_external_instrument (
443 _midnam_model_selector.get_active_text(),
444 _midnam_custom_device_mode_selector.get_active_text());
446 // Rebuild controller menu
447 _controller_menu_map.clear ();
448 delete controller_menu;
450 build_automation_action_menu(false);
454 MidiTimeAxisView::custom_device_mode_changed()
456 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
457 set_gui_property (X_("midnam-custom-device-mode"), mode);
458 _route->instrument_info().set_external_instrument (
459 _midnam_model_selector.get_active_text(), mode);
463 MidiTimeAxisView::midi_view()
465 return dynamic_cast<MidiStreamView*>(_view);
469 MidiTimeAxisView::set_height (uint32_t h)
471 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
472 _midi_controls_box.show ();
474 _midi_controls_box.hide();
477 if (h >= KEYBOARD_MIN_HEIGHT) {
478 if (is_track() && _range_scroomer) {
479 _range_scroomer->show();
481 if (is_track() && _piano_roll_header) {
482 _piano_roll_header->show();
485 if (is_track() && _range_scroomer) {
486 _range_scroomer->hide();
488 if (is_track() && _piano_roll_header) {
489 _piano_roll_header->hide();
493 /* We need to do this after changing visibility of our stuff, as it will
494 eventually trigger a call to Editor::reset_controls_layout_width(),
495 which needs to know if we have just shown or hidden a scroomer /
498 RouteTimeAxisView::set_height (h);
502 MidiTimeAxisView::append_extra_display_menu_items ()
504 using namespace Menu_Helpers;
506 MenuList& items = display_menu->items();
509 Menu *range_menu = manage(new Menu);
510 MenuList& range_items = range_menu->items();
511 range_menu->set_name ("ArdourContextMenu");
513 range_items.push_back (
514 MenuElem (_("Show Full Range"),
515 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
516 MidiStreamView::FullRange, true)));
518 range_items.push_back (
519 MenuElem (_("Fit Contents"),
520 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
521 MidiStreamView::ContentsRange, true)));
523 items.push_back (MenuElem (_("Note Range"), *range_menu));
524 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
525 items.push_back (MenuElem (_("Channel Selector"),
526 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
528 color_mode_menu = build_color_mode_menu();
529 if (color_mode_menu) {
530 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
533 items.push_back (SeparatorElem ());
537 MidiTimeAxisView::toggle_channel_selector ()
539 if (!_channel_selector) {
540 _channel_selector = new MidiChannelSelectorWindow (midi_track());
542 if (_color_mode == ChannelColors) {
543 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
545 _channel_selector->set_default_channel_color ();
548 _channel_selector->show_all ();
550 _channel_selector->cycle_visibility ();
555 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
557 using namespace Menu_Helpers;
559 /* If we have a controller menu, we need to detach it before
560 RouteTimeAxis::build_automation_action_menu destroys the
561 menu it is attached to. Otherwise GTK destroys
562 controller_menu's gobj, meaning that it can't be reattached
563 below. See bug #3134.
566 if (controller_menu) {
567 detach_menu (*controller_menu);
570 _channel_command_menu_map.clear ();
571 RouteTimeAxisView::build_automation_action_menu (for_selection);
573 MenuList& automation_items = automation_action_menu->items();
575 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
577 if (selected_channels != 0) {
579 automation_items.push_back (SeparatorElem());
581 /* these 2 MIDI "command" types are semantically more like automation
582 than note data, but they are not MIDI controllers. We give them
583 special status in this menu, since they will not show up in the
584 controller list and anyone who actually knows something about MIDI
585 (!) would not expect to find them there.
588 add_channel_command_menu_item (
589 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
590 automation_items.back().set_sensitive (
591 !for_selection || _editor.get_selection().tracks.size() == 1);
592 add_channel_command_menu_item (
593 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
594 automation_items.back().set_sensitive (
595 !for_selection || _editor.get_selection().tracks.size() == 1);
597 /* now all MIDI controllers. Always offer the possibility that we will
598 rebuild the controllers menu since it might need to be updated after
599 a channel mode change or other change. Also detach it first in case
600 it has been used anywhere else.
603 build_controller_menu ();
605 automation_items.push_back (SeparatorElem());
606 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
607 automation_items.back().set_sensitive (
608 !for_selection || _editor.get_selection().tracks.size() == 1);
610 automation_items.push_back (
611 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
612 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
615 automation_items.push_back (SeparatorElem());
616 automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility)));
617 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
618 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
619 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
621 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
623 if (!pan_tracks.empty()) {
624 automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility)));
625 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
626 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
627 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
629 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
630 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
631 _main_automation_menu_map[*p] = pan_automation_item;
638 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
640 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
642 for (uint8_t chn = 0; chn < 16; chn++) {
643 if (selected_channels & (0x0001 << chn)) {
645 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
646 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
649 menu->set_active (yn);
656 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
658 AutomationType auto_type,
661 using namespace Menu_Helpers;
663 /* count the number of selected channels because we will build a different menu
664 structure if there is more than 1 selected.
667 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
670 for (uint8_t chn = 0; chn < 16; chn++) {
671 if (selected_channels & (0x0001 << chn)) {
680 /* multiple channels - create a submenu, with 1 item per channel */
682 Menu* chn_menu = manage (new Menu);
683 MenuList& chn_items (chn_menu->items());
684 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
686 /* add a couple of items to hide/show all of them */
688 chn_items.push_back (
689 MenuElem (_("Hide all channels"),
690 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
691 false, param_without_channel)));
692 chn_items.push_back (
693 MenuElem (_("Show all channels"),
694 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
695 true, param_without_channel)));
697 for (uint8_t chn = 0; chn < 16; chn++) {
698 if (selected_channels & (0x0001 << chn)) {
700 /* for each selected channel, add a menu item for this controller */
702 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
703 chn_items.push_back (
704 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
705 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
706 fully_qualified_param)));
708 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
709 bool visible = false;
712 if (track->marked_for_display()) {
717 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
718 _channel_command_menu_map[fully_qualified_param] = cmi;
719 cmi->set_active (visible);
723 /* now create an item in the parent menu that has the per-channel list as a submenu */
725 items.push_back (MenuElem (label, *chn_menu));
729 /* just one channel - create a single menu item for this command+channel combination*/
731 for (uint8_t chn = 0; chn < 16; chn++) {
732 if (selected_channels & (0x0001 << chn)) {
734 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
736 CheckMenuElem (label,
737 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
738 fully_qualified_param)));
740 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
741 bool visible = false;
744 if (track->marked_for_display()) {
749 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
750 _channel_command_menu_map[fully_qualified_param] = cmi;
751 cmi->set_active (visible);
753 /* one channel only */
760 /** Add a single menu item for a controller on one channel. */
762 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
764 const std::string& name)
766 using namespace Menu_Helpers;
768 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
769 for (uint8_t chn = 0; chn < 16; chn++) {
770 if (selected_channels & (0x0001 << chn)) {
772 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
773 ctl_items.push_back (
775 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
777 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
778 fully_qualified_param)));
779 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
781 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
782 fully_qualified_param);
784 bool visible = false;
786 if (track->marked_for_display()) {
791 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
792 _controller_menu_map[fully_qualified_param] = cmi;
793 cmi->set_active (visible);
795 /* one channel only */
801 /** Add a submenu with 1 item per channel for a controller on many channels. */
803 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
805 const std::string& name)
807 using namespace Menu_Helpers;
809 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
811 Menu* chn_menu = manage (new Menu);
812 MenuList& chn_items (chn_menu->items());
814 /* add a couple of items to hide/show this controller on all channels */
816 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
817 chn_items.push_back (
818 MenuElem (_("Hide all channels"),
819 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
820 false, param_without_channel)));
821 chn_items.push_back (
822 MenuElem (_("Show all channels"),
823 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
824 true, param_without_channel)));
826 for (uint8_t chn = 0; chn < 16; chn++) {
827 if (selected_channels & (0x0001 << chn)) {
829 /* for each selected channel, add a menu item for this controller */
831 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
832 chn_items.push_back (
833 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
834 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
835 fully_qualified_param)));
837 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
838 fully_qualified_param);
839 bool visible = false;
842 if (track->marked_for_display()) {
847 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
848 _controller_menu_map[fully_qualified_param] = cmi;
849 cmi->set_active (visible);
853 /* add the per-channel menu to the list of controllers, with the name of the controller */
854 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
856 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
859 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
860 MidiTimeAxisView::get_device_mode()
862 using namespace MIDI::Name;
864 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
866 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
869 return device_names->custom_device_mode_by_name(
870 gui_property (X_("midnam-custom-device-mode")));
873 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
874 MidiTimeAxisView::get_device_names()
876 using namespace MIDI::Name;
878 const std::string model = gui_property (X_("midnam-model-name"));
880 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
881 .document_by_model(model);
883 return midnam->master_device_names(model);
885 return boost::shared_ptr<MasterDeviceNames>();
890 MidiTimeAxisView::build_controller_menu ()
892 using namespace Menu_Helpers;
894 if (controller_menu) {
895 /* it exists and has not been invalidated by a channel mode change */
899 controller_menu = new Menu; // explicitly managed by us
900 MenuList& items (controller_menu->items());
902 /* create several "top level" menu items for sets of controllers (16 at a
903 time), and populate each one with a submenu for each controller+channel
904 combination covering the currently selected channels for this track
907 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
909 /* count the number of selected channels because we will build a different menu
910 structure if there is more than 1 selected.
914 for (uint8_t chn = 0; chn < 16; chn++) {
915 if (selected_channels & (0x0001 << chn)) {
922 using namespace MIDI::Name;
923 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
925 if (device_names && !device_names->controls().empty()) {
926 /* Controllers names available in midnam file, generate fancy menu */
927 unsigned n_items = 0;
928 unsigned n_groups = 0;
930 /* TODO: This is not correct, should look up the currently applicable ControlNameList
931 and only build a menu for that one. */
932 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
933 l != device_names->controls().end(); ++l) {
934 boost::shared_ptr<ControlNameList> name_list = l->second;
935 Menu* ctl_menu = NULL;
937 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
938 c != name_list->controls().end();) {
939 const uint16_t ctl = c->second->number();
940 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
941 /* Skip bank select controllers since they're handled specially */
943 /* Create a new submenu */
944 ctl_menu = manage (new Menu);
947 MenuList& ctl_items (ctl_menu->items());
949 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
951 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
956 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
957 /* Submenu has 16 items or we're done, add it to controller menu and reset */
959 MenuElem(string_compose(_("Controllers %1-%2"),
960 (16 * n_groups), (16 * n_groups) + n_items - 1),
969 /* No controllers names, generate generic numeric menu */
970 for (int i = 0; i < 127; i += 16) {
971 Menu* ctl_menu = manage (new Menu);
972 MenuList& ctl_items (ctl_menu->items());
974 for (int ctl = i; ctl < i+16; ++ctl) {
975 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
976 /* Skip bank select controllers since they're handled specially */
981 add_multi_channel_controller_item(
982 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
984 add_single_channel_controller_item(
985 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
989 /* Add submenu for this block of controllers to controller menu */
991 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
998 MidiTimeAxisView::build_note_mode_menu()
1000 using namespace Menu_Helpers;
1002 Menu* mode_menu = manage (new Menu);
1003 MenuList& items = mode_menu->items();
1004 mode_menu->set_name ("ArdourContextMenu");
1006 RadioMenuItem::Group mode_group;
1008 RadioMenuElem (mode_group,_("Sustained"),
1009 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1011 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1012 _note_mode_item->set_active(_note_mode == Sustained);
1015 RadioMenuElem (mode_group, _("Percussive"),
1016 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1017 Percussive, true)));
1018 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1019 _percussion_mode_item->set_active(_note_mode == Percussive);
1025 MidiTimeAxisView::build_color_mode_menu()
1027 using namespace Menu_Helpers;
1029 Menu* mode_menu = manage (new Menu);
1030 MenuList& items = mode_menu->items();
1031 mode_menu->set_name ("ArdourContextMenu");
1033 RadioMenuItem::Group mode_group;
1035 RadioMenuElem (mode_group, _("Meter Colors"),
1036 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1037 MeterColors, false, true, true)));
1038 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1039 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1042 RadioMenuElem (mode_group, _("Channel Colors"),
1043 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1044 ChannelColors, false, true, true)));
1045 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1046 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1049 RadioMenuElem (mode_group, _("Track Color"),
1050 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1051 TrackColor, false, true, true)));
1052 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1053 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1059 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1061 if (apply_to_selection) {
1062 _editor.get_selection().tracks.foreach_midi_time_axis (
1063 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1065 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1067 midi_track()->set_note_mode(mode);
1068 set_gui_property ("note-mode", enum_2_string(_note_mode));
1069 _view->redisplay_track();
1075 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1077 if (apply_to_selection) {
1078 _editor.get_selection().tracks.foreach_midi_time_axis (
1079 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1081 if (_color_mode == mode && !force) {
1085 if (_channel_selector) {
1086 if (mode == ChannelColors) {
1087 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1089 _channel_selector->set_default_channel_color();
1094 set_gui_property ("color-mode", enum_2_string(_color_mode));
1096 _view->redisplay_track();
1102 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1104 if (apply_to_selection) {
1105 _editor.get_selection().tracks.foreach_midi_time_axis (
1106 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1108 if (!_ignore_signals) {
1109 midi_view()->set_note_range(range);
1115 MidiTimeAxisView::update_range()
1117 MidiGhostRegion* mgr;
1119 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1120 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1121 mgr->update_range();
1127 MidiTimeAxisView::ensure_pan_views (bool show)
1129 bool changed = false;
1130 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1132 (*i)->set_marked_for_display (false);
1135 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1139 if (!_route->panner()) {
1143 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1144 set<Evoral::Parameter>::iterator p;
1146 for (p = params.begin(); p != params.end(); ++p) {
1147 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1149 if (pan_control->parameter().type() == NullAutomation) {
1150 error << "Pan control has NULL automation type!" << endmsg;
1154 if (automation_child (pan_control->parameter ()).get () == 0) {
1156 /* we don't already have an AutomationTimeAxisView for this parameter */
1158 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1160 boost::shared_ptr<AutomationTimeAxisView> t (
1161 new AutomationTimeAxisView (_session,
1165 pan_control->parameter (),
1173 pan_tracks.push_back (t);
1174 add_automation_child (*p, t, show);
1176 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1182 MidiTimeAxisView::update_gain_track_visibility ()
1184 bool const showit = gain_automation_item->get_active();
1186 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1187 gain_track->set_marked_for_display (showit);
1189 /* now trigger a redisplay */
1192 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1198 MidiTimeAxisView::update_pan_track_visibility ()
1200 bool const showit = pan_automation_item->get_active();
1201 bool changed = false;
1203 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1204 if ((*i)->set_marked_for_display (showit)) {
1210 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1215 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1217 using namespace MIDI::Name;
1219 if (apply_to_selection) {
1220 _editor.get_selection().tracks.foreach_midi_time_axis (
1221 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1224 // Show existing automation
1225 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1227 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1228 create_automation_child(*i, true);
1231 // Show automation for all controllers named in midnam file
1232 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1233 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1234 device_names && !device_names->controls().empty()) {
1235 const std::string device_mode = _midnam_custom_device_mode_selector.get_active_text();
1236 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1237 for (uint32_t chn = 0; chn < 16; ++chn) {
1238 if ((selected_channels & (0x0001 << chn)) == 0) {
1239 // Channel not in use
1243 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1249 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1250 chan_names->control_list_name());
1251 if (!control_names) {
1255 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1256 c != control_names->controls().end();
1258 const uint16_t ctl = c->second->number();
1259 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1260 /* Skip bank select controllers since they're handled specially */
1261 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1262 create_automation_child(param, true);
1269 RouteTimeAxisView::show_all_automation ();
1274 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1276 if (apply_to_selection) {
1277 _editor.get_selection().tracks.foreach_midi_time_axis (
1278 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1281 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1283 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1284 create_automation_child (*i, true);
1288 RouteTimeAxisView::show_existing_automation ();
1292 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1295 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1297 if (param.type() == NullAutomation) {
1301 AutomationTracks::iterator existing = _automation_tracks.find (param);
1303 if (existing != _automation_tracks.end()) {
1305 /* automation track created because we had existing data for
1306 * the processor, but visibility may need to be controlled
1307 * since it will have been set visible by default.
1310 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1317 boost::shared_ptr<AutomationTimeAxisView> track;
1319 switch (param.type()) {
1321 case GainAutomation:
1322 create_gain_automation_child (param, show);
1325 case MuteAutomation:
1326 create_mute_automation_child (param, show);
1329 case PluginAutomation:
1330 /* handled elsewhere */
1333 case MidiCCAutomation:
1334 case MidiPgmChangeAutomation:
1335 case MidiPitchBenderAutomation:
1336 case MidiChannelPressureAutomation:
1337 case MidiSystemExclusiveAutomation:
1338 /* These controllers are region "automation" - they are owned
1339 * by regions (and their MidiModels), not by the track. As a
1340 * result we do not create an AutomationList/Line for the track
1341 * ... except here we are doing something!! XXX
1344 track.reset (new AutomationTimeAxisView (
1347 boost::shared_ptr<Automatable> (),
1348 boost::shared_ptr<AutomationControl> (),
1354 _route->describe_parameter(param)));
1357 _view->foreach_regionview (
1358 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1361 add_automation_child (param, track, show);
1364 case PanWidthAutomation:
1365 case PanElevationAutomation:
1366 case PanAzimuthAutomation:
1367 ensure_pan_views (show);
1371 error << "MidiTimeAxisView: unknown automation child "
1372 << EventTypeMap::instance().to_symbol(param) << endmsg;
1377 MidiTimeAxisView::route_active_changed ()
1379 RouteUI::route_active_changed ();
1382 if (_route->active()) {
1383 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1384 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1385 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1387 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1388 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1389 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1392 if (_route->active()) {
1393 controls_ebox.set_name ("BusControlsBaseUnselected");
1394 controls_base_selected_name = "BusControlsBaseSelected";
1395 controls_base_unselected_name = "BusControlsBaseUnselected";
1397 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1398 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1399 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1405 MidiTimeAxisView::set_note_selection (uint8_t note)
1407 if (!_editor.internal_editing()) {
1411 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1413 if (_view->num_selected_regionviews() == 0) {
1414 _view->foreach_regionview (
1415 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1418 _view->foreach_selected_regionview (
1419 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1425 MidiTimeAxisView::add_note_selection (uint8_t note)
1427 if (!_editor.internal_editing()) {
1431 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1433 if (_view->num_selected_regionviews() == 0) {
1434 _view->foreach_regionview (
1435 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1438 _view->foreach_selected_regionview (
1439 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1445 MidiTimeAxisView::extend_note_selection (uint8_t note)
1447 if (!_editor.internal_editing()) {
1451 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1453 if (_view->num_selected_regionviews() == 0) {
1454 _view->foreach_regionview (
1455 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1458 _view->foreach_selected_regionview (
1459 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1465 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1467 if (!_editor.internal_editing()) {
1471 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1473 if (_view->num_selected_regionviews() == 0) {
1474 _view->foreach_regionview (
1475 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1478 _view->foreach_selected_regionview (
1479 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1485 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1487 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1491 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1493 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1497 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1499 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1503 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1505 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1509 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1511 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1515 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1516 bool changed = false;
1520 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1522 for (uint32_t chn = 0; chn < 16; ++chn) {
1523 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1524 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1530 if ((selected_channels & (0x0001 << chn)) == 0) {
1531 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1532 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1534 changed = track->set_marked_for_display (false) || changed;
1536 changed = track->set_marked_for_display (true) || changed;
1543 /* TODO: Bender, Pressure */
1545 /* invalidate the controller menu, so that we rebuild it next time */
1546 _controller_menu_map.clear ();
1547 delete controller_menu;
1548 controller_menu = 0;
1556 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1558 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1563 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1564 if (i != _controller_menu_map.end()) {
1568 i = _channel_command_menu_map.find (param);
1569 if (i != _channel_command_menu_map.end()) {
1576 boost::shared_ptr<MidiRegion>
1577 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1579 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1581 real_editor->begin_reversible_command (Operations::create_region);
1582 playlist()->clear_changes ();
1584 real_editor->snap_to (pos, 0);
1586 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1589 plist.add (ARDOUR::Properties::start, 0);
1590 plist.add (ARDOUR::Properties::length, length);
1591 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1593 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1595 playlist()->add_region (region, pos);
1596 _session->add_command (new StatefulDiffCommand (playlist()));
1599 real_editor->commit_reversible_command ();
1602 return boost::dynamic_pointer_cast<MidiRegion>(region);
1606 MidiTimeAxisView::ensure_step_editor ()
1608 if (!_step_editor) {
1609 _step_editor = new StepEditor (_editor, midi_track(), *this);
1614 MidiTimeAxisView::start_step_editing ()
1616 ensure_step_editor ();
1617 _step_editor->start_step_editing ();
1621 MidiTimeAxisView::stop_step_editing ()
1624 _step_editor->stop_step_editing ();
1628 /** @return channel (counted from 0) to add an event to, based on the current setting
1629 * of the channel selector.
1632 MidiTimeAxisView::get_channel_for_add () const
1634 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1636 uint8_t channel = 0;
1638 /* pick the highest selected channel, unless all channels are selected,
1639 which is interpreted to mean channel 1 (zero)
1642 for (uint16_t i = 0; i < 16; ++i) {
1643 if (chn_mask & (1<<i)) {
1649 if (chn_cnt == 16) {
1657 MidiTimeAxisView::note_range_changed ()
1659 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1660 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1664 MidiTimeAxisView::contents_height_changed ()
1666 _range_scroomer->set_size_request (-1, _view->child_height ());
1670 MidiTimeAxisView::playback_channel_mode_changed ()
1672 switch (midi_track()->get_playback_channel_mode()) {
1674 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1676 case FilterChannels:
1677 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1680 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1686 MidiTimeAxisView::capture_channel_mode_changed ()
1688 switch (midi_track()->get_capture_channel_mode()) {
1690 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1692 case FilterChannels:
1693 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1696 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));