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.
22 #include <strings.h> // for ffs(3)
28 #include <sigc++/bind.h>
30 #include "pbd/error.h"
31 #include "pbd/stl_delete.h"
32 #include "pbd/whitespace.h"
33 #include "pbd/basename.h"
34 #include "pbd/enumwriter.h"
35 #include "pbd/memento_command.h"
36 #include "pbd/stateful_diff_command.h"
38 #include "gtkmm2ext/gtk_ui.h"
39 #include "gtkmm2ext/selector.h"
40 #include "gtkmm2ext/bindable_button.h"
41 #include "gtkmm2ext/utils.h"
43 #include "ardour/event_type_map.h"
44 #include "ardour/midi_patch_manager.h"
45 #include "ardour/midi_playlist.h"
46 #include "ardour/midi_region.h"
47 #include "ardour/midi_source.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/pannable.h"
51 #include "ardour/panner.h"
52 #include "ardour/panner_shell.h"
53 #include "ardour/playlist.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"
67 #include "canvas-note-event.h"
68 #include "canvas_impl.h"
71 #include "ghostregion.h"
72 #include "gui_thread.h"
74 #include "midi_channel_selector.h"
75 #include "midi_scroomer.h"
76 #include "midi_streamview.h"
77 #include "midi_region_view.h"
78 #include "midi_time_axis.h"
79 #include "piano_roll_header.h"
80 #include "playlist_selector.h"
81 #include "plugin_selector.h"
82 #include "plugin_ui.h"
83 #include "point_selection.h"
85 #include "region_view.h"
86 #include "rgb_macros.h"
87 #include "selection.h"
88 #include "step_editor.h"
89 #include "simplerect.h"
92 #include "ardour/midi_track.h"
96 using namespace ARDOUR;
99 using namespace Gtkmm2ext;
100 using namespace Editing;
102 // Minimum height at which a control is displayed
103 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 140;
104 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
106 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
107 : AxisView(sess) // virtually inherited
108 , RouteTimeAxisView(ed, sess, canvas)
109 , _ignore_signals(false)
111 , _piano_roll_header(0)
112 , _note_mode(Sustained)
114 , _percussion_mode_item(0)
115 , _color_mode(MeterColors)
116 , _meter_color_mode_item(0)
117 , _channel_color_mode_item(0)
118 , _track_color_mode_item(0)
119 , _channel_selector (0)
120 , _step_edit_item (0)
121 , controller_menu (0)
127 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
131 _view = new MidiStreamView (*this);
134 _piano_roll_header = new PianoRollHeader(*midi_view());
135 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
136 _range_scroomer->DoubleClicked.connect (
137 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
138 MidiStreamView::ContentsRange, false));
141 /* This next call will result in our height being set up, so it must come after
142 the creation of the piano roll / range scroomer as their visibility is set up
145 RouteTimeAxisView::set_route (rt);
147 _view->apply_color (_color, StreamView::RegionColor);
149 subplugin_menu.set_name ("ArdourContextMenu");
151 if (!gui_property ("note-range-min").empty ()) {
152 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
153 atoi (gui_property ("note-range-max").c_str()),
157 midi_view()->NoteRangeChanged.connect (
158 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
159 _view->ContentsHeightChanged.connect (
160 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
162 ignore_toggle = false;
164 if (is_midi_track()) {
165 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
166 _note_mode = midi_track()->note_mode();
167 } else { // MIDI bus (which doesn't exist yet..)
168 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
171 /* if set_state above didn't create a gain automation child, we need to make one */
172 if (automation_child (GainAutomation) == 0) {
173 create_automation_child (GainAutomation, false);
176 if (_route->panner_shell()) {
177 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
180 /* map current state of the route */
181 ensure_pan_views (false);
183 processors_changed (RouteProcessorChange ());
185 _route->processors_changed.connect (*this, invalidator (*this),
186 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
190 _piano_roll_header->SetNoteSelection.connect (
191 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
192 _piano_roll_header->AddNoteSelection.connect (
193 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
194 _piano_roll_header->ExtendNoteSelection.connect (
195 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
196 _piano_roll_header->ToggleNoteSelection.connect (
197 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
199 /* Suspend updates of the StreamView during scroomer drags to speed things up */
200 _range_scroomer->DragStarting.connect (
201 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
202 _range_scroomer->DragFinishing.connect (
203 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
205 /* Put the scroomer and the keyboard in a VBox with a padding
206 label so that they can be reduced in height for stacked-view
209 VBox* v = manage (new VBox);
210 HBox* h = manage (new HBox);
211 h->pack_start (*_range_scroomer);
212 h->pack_start (*_piano_roll_header);
213 v->pack_start (*h, false, false);
214 v->pack_start (*manage (new Label ("")), true, true);
217 controls_hbox.pack_start(*v, false, false);
219 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
220 controls_base_selected_name = "MidiTrackControlsBaseSelected";
221 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
223 midi_view()->NoteRangeChanged.connect (
224 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
226 /* ask for notifications of any new RegionViews */
227 _view->RegionViewAdded.connect (
228 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
230 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
231 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
233 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
234 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
236 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
237 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
239 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
240 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
243 playback_channel_mode_changed ();
244 capture_channel_mode_changed ();
246 if (!_editor.have_idled()) {
247 /* first idle will do what we need */
253 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
255 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
256 for (; m != patch_manager.all_models().end(); ++m) {
257 _midnam_model_selector.append_text(m->c_str());
260 if (gui_property (X_("midnam-model-name")).empty()) {
261 set_gui_property (X_("midnam-model-name"), "Generic");
264 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
265 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
267 set_gui_property (X_("midnam-custom-device-mode"),
268 *device_names->custom_device_mode_names().begin());
272 _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
273 _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
275 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
276 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
278 _midi_controls_box.set_homogeneous(false);
279 _midi_controls_box.set_border_width (10);
281 _channel_status_box.set_homogeneous (false);
282 _channel_status_box.set_spacing (6);
284 _channel_selector_button.set_label (_("Chns"));
285 ARDOUR_UI::instance()->set_tip (_channel_selector_button, _("Click to edit channel settings"));
287 /* fixed sized labels to prevent silly nonsense (though obviously,
288 * they cause their own too)
291 _playback_channel_status.set_size_request (65, -1);
292 _capture_channel_status.set_size_request (60, -1);
294 _channel_status_box.pack_start (_playback_channel_status, false, false);
295 _channel_status_box.pack_start (_capture_channel_status, false, false);
296 _channel_status_box.pack_start (_channel_selector_button, false, false);
297 _channel_status_box.show_all ();
299 _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
301 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
303 if (!patch_manager.all_models().empty()) {
305 _midnam_model_selector.set_size_request(22, 30);
306 _midnam_model_selector.set_border_width(2);
307 _midnam_model_selector.show ();
308 _midi_controls_box.pack_start (_midnam_model_selector);
310 _midnam_custom_device_mode_selector.set_size_request(10, 30);
311 _midnam_custom_device_mode_selector.set_border_width(2);
312 _midnam_custom_device_mode_selector.show ();
314 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
318 custom_device_mode_changed();
320 _midnam_model_selector.signal_changed().connect(
321 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
322 _midnam_custom_device_mode_selector.signal_changed().connect(
323 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
325 controls_vbox.pack_start(_midi_controls_box, false, false);
327 const string color_mode = gui_property ("color-mode");
328 if (!color_mode.empty()) {
329 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
330 if (_channel_selector && _color_mode == ChannelColors) {
331 _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
335 set_color_mode (_color_mode, true, false);
337 const string note_mode = gui_property ("note-mode");
338 if (!note_mode.empty()) {
339 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
340 if (_percussion_mode_item) {
341 _percussion_mode_item->set_active (_note_mode == Percussive);
345 /* Look for any GUI object state nodes that represent automation children
346 * that should exist, and create the children.
349 const list<string> gui_ids = gui_object_state().all_ids ();
350 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
353 Evoral::Parameter parameter (0, 0, 0);
355 bool const p = AutomationTimeAxisView::parse_state_id (
356 *i, route_id, has_parameter, parameter);
357 if (p && route_id == _route->id () && has_parameter) {
358 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
359 create_automation_child (parameter, string_is_affirmative (visible));
365 MidiTimeAxisView::first_idle ()
372 MidiTimeAxisView::~MidiTimeAxisView ()
374 delete _channel_selector;
376 delete _piano_roll_header;
377 _piano_roll_header = 0;
379 delete _range_scroomer;
382 delete controller_menu;
387 MidiTimeAxisView::enter_internal_edit_mode ()
390 midi_view()->enter_internal_edit_mode ();
395 MidiTimeAxisView::leave_internal_edit_mode ()
398 midi_view()->leave_internal_edit_mode ();
403 MidiTimeAxisView::check_step_edit ()
405 ensure_step_editor ();
406 _step_editor->check_step_edit ();
410 MidiTimeAxisView::model_changed()
412 const Glib::ustring model = _midnam_model_selector.get_active_text();
413 set_gui_property (X_("midnam-model-name"), model);
415 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
416 .custom_device_mode_names_by_model(model);
418 _midnam_custom_device_mode_selector.clear_items();
420 for (std::list<std::string>::const_iterator i = device_modes.begin();
421 i != device_modes.end(); ++i) {
422 _midnam_custom_device_mode_selector.append_text(*i);
425 _midnam_custom_device_mode_selector.set_active(0);
427 _route->instrument_info().set_external_instrument (
428 _midnam_model_selector.get_active_text(),
429 _midnam_custom_device_mode_selector.get_active_text());
431 // Rebuild controller menu
432 _controller_menu_map.clear ();
433 delete controller_menu;
435 build_automation_action_menu(false);
439 MidiTimeAxisView::custom_device_mode_changed()
441 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
442 set_gui_property (X_("midnam-custom-device-mode"), mode);
443 _route->instrument_info().set_external_instrument (
444 _midnam_model_selector.get_active_text(), mode);
448 MidiTimeAxisView::midi_view()
450 return dynamic_cast<MidiStreamView*>(_view);
454 MidiTimeAxisView::set_height (uint32_t h)
456 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
457 _midi_controls_box.show ();
459 _midi_controls_box.hide();
462 if (h >= KEYBOARD_MIN_HEIGHT) {
463 if (is_track() && _range_scroomer) {
464 _range_scroomer->show();
466 if (is_track() && _piano_roll_header) {
467 _piano_roll_header->show();
470 if (is_track() && _range_scroomer) {
471 _range_scroomer->hide();
473 if (is_track() && _piano_roll_header) {
474 _piano_roll_header->hide();
478 /* We need to do this after changing visibility of our stuff, as it will
479 eventually trigger a call to Editor::reset_controls_layout_width(),
480 which needs to know if we have just shown or hidden a scroomer /
483 RouteTimeAxisView::set_height (h);
487 MidiTimeAxisView::append_extra_display_menu_items ()
489 using namespace Menu_Helpers;
491 MenuList& items = display_menu->items();
494 Menu *range_menu = manage(new Menu);
495 MenuList& range_items = range_menu->items();
496 range_menu->set_name ("ArdourContextMenu");
498 range_items.push_back (
499 MenuElem (_("Show Full Range"),
500 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
501 MidiStreamView::FullRange, true)));
503 range_items.push_back (
504 MenuElem (_("Fit Contents"),
505 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
506 MidiStreamView::ContentsRange, true)));
508 items.push_back (MenuElem (_("Note Range"), *range_menu));
509 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
510 items.push_back (MenuElem (_("Channel Selector"),
511 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
513 color_mode_menu = build_color_mode_menu();
514 if (color_mode_menu) {
515 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
518 items.push_back (SeparatorElem ());
522 MidiTimeAxisView::toggle_channel_selector ()
524 if (!_channel_selector) {
525 _channel_selector = new MidiChannelSelectorWindow (midi_track());
527 if (_color_mode == ChannelColors) {
528 _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
530 _channel_selector->set_default_channel_color ();
533 _channel_selector->show_all ();
535 _channel_selector->cycle_visibility ();
540 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
542 using namespace Menu_Helpers;
544 /* If we have a controller menu, we need to detach it before
545 RouteTimeAxis::build_automation_action_menu destroys the
546 menu it is attached to. Otherwise GTK destroys
547 controller_menu's gobj, meaning that it can't be reattached
548 below. See bug #3134.
551 if (controller_menu) {
552 detach_menu (*controller_menu);
555 _channel_command_menu_map.clear ();
556 RouteTimeAxisView::build_automation_action_menu (for_selection);
558 MenuList& automation_items = automation_action_menu->items();
560 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
562 if (selected_channels != 0) {
564 automation_items.push_back (SeparatorElem());
566 /* these 2 MIDI "command" types are semantically more like automation
567 than note data, but they are not MIDI controllers. We give them
568 special status in this menu, since they will not show up in the
569 controller list and anyone who actually knows something about MIDI
570 (!) would not expect to find them there.
573 add_channel_command_menu_item (
574 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
575 automation_items.back().set_sensitive (
576 !for_selection || _editor.get_selection().tracks.size() == 1);
577 add_channel_command_menu_item (
578 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
579 automation_items.back().set_sensitive (
580 !for_selection || _editor.get_selection().tracks.size() == 1);
582 /* now all MIDI controllers. Always offer the possibility that we will
583 rebuild the controllers menu since it might need to be updated after
584 a channel mode change or other change. Also detach it first in case
585 it has been used anywhere else.
588 build_controller_menu ();
590 automation_items.push_back (SeparatorElem());
591 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
592 automation_items.back().set_sensitive (
593 !for_selection || _editor.get_selection().tracks.size() == 1);
595 automation_items.push_back (
596 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
597 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
600 automation_items.push_back (SeparatorElem());
601 automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility)));
602 gain_automation_item = dynamic_cast<CheckMenuItem*> (&automation_items.back ());
603 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
604 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
606 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
608 if (!pan_tracks.empty()) {
609 automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility)));
610 pan_automation_item = dynamic_cast<CheckMenuItem*> (&automation_items.back ());
611 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
612 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
614 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
615 for (set<Evoral::Parameter>::iterator p = params.begin(); p != params.end(); ++p) {
616 _main_automation_menu_map[*p] = pan_automation_item;
623 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
625 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
627 for (uint8_t chn = 0; chn < 16; chn++) {
628 if (selected_channels & (0x0001 << chn)) {
630 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
631 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
634 menu->set_active (yn);
641 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
643 AutomationType auto_type,
646 using namespace Menu_Helpers;
648 /* count the number of selected channels because we will build a different menu
649 structure if there is more than 1 selected.
652 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
655 for (uint8_t chn = 0; chn < 16; chn++) {
656 if (selected_channels & (0x0001 << chn)) {
665 /* multiple channels - create a submenu, with 1 item per channel */
667 Menu* chn_menu = manage (new Menu);
668 MenuList& chn_items (chn_menu->items());
669 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
671 /* add a couple of items to hide/show all of them */
673 chn_items.push_back (
674 MenuElem (_("Hide all channels"),
675 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
676 false, param_without_channel)));
677 chn_items.push_back (
678 MenuElem (_("Show all channels"),
679 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
680 true, param_without_channel)));
682 for (uint8_t chn = 0; chn < 16; chn++) {
683 if (selected_channels & (0x0001 << chn)) {
685 /* for each selected channel, add a menu item for this controller */
687 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
688 chn_items.push_back (
689 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
690 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
691 fully_qualified_param)));
693 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
694 bool visible = false;
697 if (track->marked_for_display()) {
702 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
703 _channel_command_menu_map[fully_qualified_param] = cmi;
704 cmi->set_active (visible);
708 /* now create an item in the parent menu that has the per-channel list as a submenu */
710 items.push_back (MenuElem (label, *chn_menu));
714 /* just one channel - create a single menu item for this command+channel combination*/
716 for (uint8_t chn = 0; chn < 16; chn++) {
717 if (selected_channels & (0x0001 << chn)) {
719 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
721 CheckMenuElem (label,
722 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
723 fully_qualified_param)));
725 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
726 bool visible = false;
729 if (track->marked_for_display()) {
734 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
735 _channel_command_menu_map[fully_qualified_param] = cmi;
736 cmi->set_active (visible);
738 /* one channel only */
745 /** Add a single menu item for a controller on one channel. */
747 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
749 const std::string& name)
751 using namespace Menu_Helpers;
753 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
754 for (uint8_t chn = 0; chn < 16; chn++) {
755 if (selected_channels & (0x0001 << chn)) {
757 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
758 ctl_items.push_back (
760 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
762 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
763 fully_qualified_param)));
764 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
766 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
767 fully_qualified_param);
769 bool visible = false;
771 if (track->marked_for_display()) {
776 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
777 _controller_menu_map[fully_qualified_param] = cmi;
778 cmi->set_active (visible);
780 /* one channel only */
786 /** Add a submenu with 1 item per channel for a controller on many channels. */
788 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
790 const std::string& name)
792 using namespace Menu_Helpers;
794 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
796 Menu* chn_menu = manage (new Menu);
797 MenuList& chn_items (chn_menu->items());
799 /* add a couple of items to hide/show this controller on all channels */
801 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
802 chn_items.push_back (
803 MenuElem (_("Hide all channels"),
804 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
805 false, param_without_channel)));
806 chn_items.push_back (
807 MenuElem (_("Show all channels"),
808 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
809 true, param_without_channel)));
811 for (uint8_t chn = 0; chn < 16; chn++) {
812 if (selected_channels & (0x0001 << chn)) {
814 /* for each selected channel, add a menu item for this controller */
816 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
817 chn_items.push_back (
818 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
819 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
820 fully_qualified_param)));
822 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
823 fully_qualified_param);
824 bool visible = false;
827 if (track->marked_for_display()) {
832 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
833 _controller_menu_map[fully_qualified_param] = cmi;
834 cmi->set_active (visible);
838 /* add the per-channel menu to the list of controllers, with the name of the controller */
839 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
841 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
844 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
845 MidiTimeAxisView::get_device_mode()
847 using namespace MIDI::Name;
849 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
851 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
854 return device_names->custom_device_mode_by_name(
855 gui_property (X_("midnam-custom-device-mode")));
858 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
859 MidiTimeAxisView::get_device_names()
861 using namespace MIDI::Name;
863 const std::string model = gui_property (X_("midnam-model-name"));
865 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
866 .document_by_model(model);
868 return midnam->master_device_names(model);
870 return boost::shared_ptr<MasterDeviceNames>();
875 MidiTimeAxisView::build_controller_menu ()
877 using namespace Menu_Helpers;
879 if (controller_menu) {
880 /* it exists and has not been invalidated by a channel mode change */
884 controller_menu = new Menu; // explicitly managed by us
885 MenuList& items (controller_menu->items());
887 /* create several "top level" menu items for sets of controllers (16 at a
888 time), and populate each one with a submenu for each controller+channel
889 combination covering the currently selected channels for this track
892 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
894 /* count the number of selected channels because we will build a different menu
895 structure if there is more than 1 selected.
899 for (uint8_t chn = 0; chn < 16; chn++) {
900 if (selected_channels & (0x0001 << chn)) {
907 using namespace MIDI::Name;
908 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
910 if (device_names && !device_names->controls().empty()) {
911 /* Controllers names available in midnam file, generate fancy menu */
912 unsigned n_items = 0;
913 unsigned n_groups = 0;
915 /* TODO: This is not correct, should look up the currently applicable ControlNameList
916 and only build a menu for that one. */
917 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
918 l != device_names->controls().end(); ++l) {
919 boost::shared_ptr<ControlNameList> name_list = l->second;
920 Menu* ctl_menu = NULL;
922 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
923 c != name_list->controls().end();) {
924 const uint16_t ctl = c->second->number();
925 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
926 /* Skip bank select controllers since they're handled specially */
928 /* Create a new submenu */
929 ctl_menu = manage (new Menu);
932 MenuList& ctl_items (ctl_menu->items());
934 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
936 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
941 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
942 /* Submenu has 16 items or we're done, add it to controller menu and reset */
944 MenuElem(string_compose(_("Controllers %1-%2"),
945 (16 * n_groups), (16 * n_groups) + n_items - 1),
954 /* No controllers names, generate generic numeric menu */
955 for (int i = 0; i < 127; i += 16) {
956 Menu* ctl_menu = manage (new Menu);
957 MenuList& ctl_items (ctl_menu->items());
959 for (int ctl = i; ctl < i+16; ++ctl) {
960 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
961 /* Skip bank select controllers since they're handled specially */
966 add_multi_channel_controller_item(
967 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
969 add_single_channel_controller_item(
970 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
974 /* Add submenu for this block of controllers to controller menu */
976 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
983 MidiTimeAxisView::build_note_mode_menu()
985 using namespace Menu_Helpers;
987 Menu* mode_menu = manage (new Menu);
988 MenuList& items = mode_menu->items();
989 mode_menu->set_name ("ArdourContextMenu");
991 RadioMenuItem::Group mode_group;
993 RadioMenuElem (mode_group,_("Sustained"),
994 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
996 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
997 _note_mode_item->set_active(_note_mode == Sustained);
1000 RadioMenuElem (mode_group, _("Percussive"),
1001 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1002 Percussive, true)));
1003 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1004 _percussion_mode_item->set_active(_note_mode == Percussive);
1010 MidiTimeAxisView::build_color_mode_menu()
1012 using namespace Menu_Helpers;
1014 Menu* mode_menu = manage (new Menu);
1015 MenuList& items = mode_menu->items();
1016 mode_menu->set_name ("ArdourContextMenu");
1018 RadioMenuItem::Group mode_group;
1020 RadioMenuElem (mode_group, _("Meter Colors"),
1021 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1022 MeterColors, false, true, true)));
1023 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1024 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1027 RadioMenuElem (mode_group, _("Channel Colors"),
1028 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1029 ChannelColors, false, true, true)));
1030 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1031 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1034 RadioMenuElem (mode_group, _("Track Color"),
1035 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1036 TrackColor, false, true, true)));
1037 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1038 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1044 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1046 if (apply_to_selection) {
1047 _editor.get_selection().tracks.foreach_midi_time_axis (
1048 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1050 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1052 midi_track()->set_note_mode(mode);
1053 set_gui_property ("note-mode", enum_2_string(_note_mode));
1054 _view->redisplay_track();
1060 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1062 if (apply_to_selection) {
1063 _editor.get_selection().tracks.foreach_midi_time_axis (
1064 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1066 if (_color_mode == mode && !force) {
1070 if (_channel_selector) {
1071 if (mode == ChannelColors) {
1072 _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
1074 _channel_selector->set_default_channel_color();
1079 set_gui_property ("color-mode", enum_2_string(_color_mode));
1081 _view->redisplay_track();
1087 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1089 if (apply_to_selection) {
1090 _editor.get_selection().tracks.foreach_midi_time_axis (
1091 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1093 if (!_ignore_signals) {
1094 midi_view()->set_note_range(range);
1100 MidiTimeAxisView::update_range()
1102 MidiGhostRegion* mgr;
1104 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1105 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1106 mgr->update_range();
1112 MidiTimeAxisView::ensure_pan_views (bool show)
1114 bool changed = false;
1115 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1117 (*i)->set_marked_for_display (false);
1120 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1124 if (!_route->panner()) {
1128 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1129 set<Evoral::Parameter>::iterator p;
1131 for (p = params.begin(); p != params.end(); ++p) {
1132 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1134 if (pan_control->parameter().type() == NullAutomation) {
1135 error << "Pan control has NULL automation type!" << endmsg;
1139 if (automation_child (pan_control->parameter ()).get () == 0) {
1141 /* we don't already have an AutomationTimeAxisView for this parameter */
1143 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1145 boost::shared_ptr<AutomationTimeAxisView> t (
1146 new AutomationTimeAxisView (_session,
1150 pan_control->parameter (),
1158 pan_tracks.push_back (t);
1159 add_automation_child (*p, t, show);
1161 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1167 MidiTimeAxisView::update_gain_track_visibility ()
1169 bool const showit = gain_automation_item->get_active();
1171 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1172 gain_track->set_marked_for_display (showit);
1174 /* now trigger a redisplay */
1177 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1183 MidiTimeAxisView::update_pan_track_visibility ()
1185 bool const showit = pan_automation_item->get_active();
1186 bool changed = false;
1188 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1189 if ((*i)->set_marked_for_display (showit)) {
1195 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1200 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1202 using namespace MIDI::Name;
1204 if (apply_to_selection) {
1205 _editor.get_selection().tracks.foreach_midi_time_axis (
1206 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1209 // Show existing automation
1210 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1212 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1213 create_automation_child(*i, true);
1216 // Show automation for all controllers named in midnam file
1217 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1218 if (device_names && !device_names->controls().empty()) {
1219 const std::string device_mode = _midnam_custom_device_mode_selector.get_active_text();
1220 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1221 for (uint32_t chn = 0; chn < 16; ++chn) {
1222 if ((selected_channels & (0x0001 << chn)) == 0) {
1223 // Channel not in use
1227 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1233 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1234 chan_names->control_list_name());
1235 if (!control_names) {
1239 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1240 c != control_names->controls().end();
1242 const uint16_t ctl = c->second->number();
1243 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1244 /* Skip bank select controllers since they're handled specially */
1245 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1246 create_automation_child(param, true);
1253 RouteTimeAxisView::show_all_automation ();
1258 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1260 if (apply_to_selection) {
1261 _editor.get_selection().tracks.foreach_midi_time_axis (
1262 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1265 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1267 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1268 create_automation_child (*i, true);
1272 RouteTimeAxisView::show_existing_automation ();
1276 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1279 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1281 if (param.type() == NullAutomation) {
1285 AutomationTracks::iterator existing = _automation_tracks.find (param);
1287 if (existing != _automation_tracks.end()) {
1289 /* automation track created because we had existing data for
1290 * the processor, but visibility may need to be controlled
1291 * since it will have been set visible by default.
1294 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1301 boost::shared_ptr<AutomationTimeAxisView> track;
1303 switch (param.type()) {
1305 case GainAutomation:
1306 create_gain_automation_child (param, show);
1309 case PluginAutomation:
1310 /* handled elsewhere */
1313 case MidiCCAutomation:
1314 case MidiPgmChangeAutomation:
1315 case MidiPitchBenderAutomation:
1316 case MidiChannelPressureAutomation:
1317 case MidiSystemExclusiveAutomation:
1318 /* These controllers are region "automation" - they are owned
1319 * by regions (and their MidiModels), not by the track. As a
1320 * result we do not create an AutomationList/Line for the track
1321 * ... except here we are doing something!! XXX
1324 track.reset (new AutomationTimeAxisView (
1327 boost::shared_ptr<Automatable> (),
1328 boost::shared_ptr<AutomationControl> (),
1334 _route->describe_parameter(param)));
1337 _view->foreach_regionview (
1338 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1341 add_automation_child (param, track, show);
1344 case PanWidthAutomation:
1345 case PanElevationAutomation:
1346 case PanAzimuthAutomation:
1347 ensure_pan_views (show);
1351 error << "MidiTimeAxisView: unknown automation child "
1352 << EventTypeMap::instance().to_symbol(param) << endmsg;
1357 MidiTimeAxisView::route_active_changed ()
1359 RouteUI::route_active_changed ();
1362 if (_route->active()) {
1363 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1364 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1365 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1367 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1368 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1369 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1372 if (_route->active()) {
1373 controls_ebox.set_name ("BusControlsBaseUnselected");
1374 controls_base_selected_name = "BusControlsBaseSelected";
1375 controls_base_unselected_name = "BusControlsBaseUnselected";
1377 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1378 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1379 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1385 MidiTimeAxisView::set_note_selection (uint8_t note)
1387 if (!_editor.internal_editing()) {
1391 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1393 if (_view->num_selected_regionviews() == 0) {
1394 _view->foreach_regionview (
1395 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1398 _view->foreach_selected_regionview (
1399 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1405 MidiTimeAxisView::add_note_selection (uint8_t note)
1407 if (!_editor.internal_editing()) {
1411 const 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::add_note_selection_region_view),
1418 _view->foreach_selected_regionview (
1419 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1425 MidiTimeAxisView::extend_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::extend_note_selection_region_view),
1438 _view->foreach_selected_regionview (
1439 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1445 MidiTimeAxisView::toggle_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::toggle_note_selection_region_view),
1458 _view->foreach_selected_regionview (
1459 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1465 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1467 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1471 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1473 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1477 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1479 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1483 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1485 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1489 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1491 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1495 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1496 bool changed = false;
1500 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1502 for (uint32_t chn = 0; chn < 16; ++chn) {
1503 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1504 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1510 if ((selected_channels & (0x0001 << chn)) == 0) {
1511 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1512 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1514 changed = track->set_marked_for_display (false) || changed;
1516 changed = track->set_marked_for_display (true) || changed;
1523 /* TODO: Bender, Pressure */
1525 /* invalidate the controller menu, so that we rebuild it next time */
1526 _controller_menu_map.clear ();
1527 delete controller_menu;
1528 controller_menu = 0;
1536 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1538 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1543 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1544 if (i != _controller_menu_map.end()) {
1548 i = _channel_command_menu_map.find (param);
1549 if (i != _channel_command_menu_map.end()) {
1556 boost::shared_ptr<MidiRegion>
1557 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1559 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1561 real_editor->begin_reversible_command (Operations::create_region);
1562 playlist()->clear_changes ();
1564 real_editor->snap_to (pos, 0);
1566 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1569 plist.add (ARDOUR::Properties::start, 0);
1570 plist.add (ARDOUR::Properties::length, length);
1571 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1573 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1575 playlist()->add_region (region, pos);
1576 _session->add_command (new StatefulDiffCommand (playlist()));
1579 real_editor->commit_reversible_command ();
1582 return boost::dynamic_pointer_cast<MidiRegion>(region);
1586 MidiTimeAxisView::ensure_step_editor ()
1588 if (!_step_editor) {
1589 _step_editor = new StepEditor (_editor, midi_track(), *this);
1594 MidiTimeAxisView::start_step_editing ()
1596 ensure_step_editor ();
1597 _step_editor->start_step_editing ();
1601 MidiTimeAxisView::stop_step_editing ()
1604 _step_editor->stop_step_editing ();
1608 /** @return channel (counted from 0) to add an event to, based on the current setting
1609 * of the channel selector.
1612 MidiTimeAxisView::get_channel_for_add () const
1614 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1616 uint8_t channel = 0;
1618 /* pick the highest selected channel, unless all channels are selected,
1619 which is interpreted to mean channel 1 (zero)
1622 for (uint16_t i = 0; i < 16; ++i) {
1623 if (chn_mask & (1<<i)) {
1629 if (chn_cnt == 16) {
1637 MidiTimeAxisView::note_range_changed ()
1639 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1640 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1644 MidiTimeAxisView::contents_height_changed ()
1646 _range_scroomer->set_size_request (-1, _view->child_height ());
1650 MidiTimeAxisView::playback_channel_mode_changed ()
1652 switch (midi_track()->get_playback_channel_mode()) {
1654 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1656 case FilterChannels:
1657 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1660 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), ffs (midi_track()->get_playback_channel_mask())));
1666 MidiTimeAxisView::capture_channel_mode_changed ()
1668 switch (midi_track()->get_capture_channel_mode()) {
1670 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1672 case FilterChannels:
1673 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1676 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), ffs (midi_track()->get_capture_channel_mask())));