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/region.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/route.h"
56 #include "ardour/session.h"
57 #include "ardour/session_object.h"
58 #include "ardour/source.h"
59 #include "ardour/track.h"
60 #include "ardour/types.h"
62 #include "ardour_ui.h"
63 #include "ardour_button.h"
64 #include "automation_line.h"
65 #include "automation_time_axis.h"
68 #include "ghostregion.h"
69 #include "gui_thread.h"
71 #include "midi_channel_selector.h"
72 #include "midi_scroomer.h"
73 #include "midi_streamview.h"
74 #include "midi_region_view.h"
75 #include "midi_time_axis.h"
76 #include "piano_roll_header.h"
77 #include "playlist_selector.h"
78 #include "plugin_selector.h"
79 #include "plugin_ui.h"
80 #include "point_selection.h"
82 #include "region_view.h"
83 #include "rgb_macros.h"
84 #include "selection.h"
85 #include "step_editor.h"
87 #include "note_base.h"
89 #include "ardour/midi_track.h"
93 using namespace ARDOUR;
94 using namespace ARDOUR_UI_UTILS;
97 using namespace Gtkmm2ext;
98 using namespace Editing;
100 // Minimum height at which a control is displayed
101 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 140;
102 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
104 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
105 : AxisView(sess) // virtually inherited
106 , RouteTimeAxisView(ed, sess, canvas)
107 , _ignore_signals(false)
109 , _piano_roll_header(0)
110 , _note_mode(Sustained)
112 , _percussion_mode_item(0)
113 , _color_mode(MeterColors)
114 , _meter_color_mode_item(0)
115 , _channel_color_mode_item(0)
116 , _track_color_mode_item(0)
117 , _channel_selector (0)
118 , _step_edit_item (0)
119 , controller_menu (0)
125 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
129 _view = new MidiStreamView (*this);
132 _piano_roll_header = new PianoRollHeader(*midi_view());
133 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
134 _range_scroomer->DoubleClicked.connect (
135 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
136 MidiStreamView::ContentsRange, false));
139 /* This next call will result in our height being set up, so it must come after
140 the creation of the piano roll / range scroomer as their visibility is set up
143 RouteTimeAxisView::set_route (rt);
145 _view->apply_color (_color, StreamView::RegionColor);
147 subplugin_menu.set_name ("ArdourContextMenu");
149 if (!gui_property ("note-range-min").empty ()) {
150 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
151 atoi (gui_property ("note-range-max").c_str()),
155 midi_view()->NoteRangeChanged.connect (
156 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
157 _view->ContentsHeightChanged.connect (
158 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
160 ignore_toggle = false;
162 if (is_midi_track()) {
163 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
164 _note_mode = midi_track()->note_mode();
165 } else { // MIDI bus (which doesn't exist yet..)
166 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
169 /* if set_state above didn't create a gain automation child, we need to make one */
170 if (automation_child (GainAutomation) == 0) {
171 create_automation_child (GainAutomation, false);
174 /* if set_state above didn't create a mute automation child, we need to make one */
175 if (automation_child (MuteAutomation) == 0) {
176 create_automation_child (MuteAutomation, false);
179 if (_route->panner_shell()) {
180 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
183 /* map current state of the route */
184 ensure_pan_views (false);
186 processors_changed (RouteProcessorChange ());
188 _route->processors_changed.connect (*this, invalidator (*this),
189 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
193 _piano_roll_header->SetNoteSelection.connect (
194 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
195 _piano_roll_header->AddNoteSelection.connect (
196 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
197 _piano_roll_header->ExtendNoteSelection.connect (
198 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
199 _piano_roll_header->ToggleNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
202 /* Suspend updates of the StreamView during scroomer drags to speed things up */
203 _range_scroomer->DragStarting.connect (
204 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
205 _range_scroomer->DragFinishing.connect (
206 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
208 /* Put the scroomer and the keyboard in a VBox with a padding
209 label so that they can be reduced in height for stacked-view
212 VBox* v = manage (new VBox);
213 HBox* h = manage (new HBox);
214 h->pack_start (*_range_scroomer);
215 h->pack_start (*_piano_roll_header);
216 v->pack_start (*h, false, false);
217 v->pack_start (*manage (new Label ("")), true, true);
220 top_hbox.pack_start(*v, false, false);
222 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
223 controls_base_selected_name = "MidiTrackControlsBaseSelected";
224 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
226 midi_view()->NoteRangeChanged.connect (
227 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
229 /* ask for notifications of any new RegionViews */
230 _view->RegionViewAdded.connect (
231 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
233 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
234 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
236 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
237 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
239 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
240 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
242 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
243 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
246 playback_channel_mode_changed ();
247 capture_channel_mode_changed ();
249 if (!_editor.have_idled()) {
250 /* first idle will do what we need */
256 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
258 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
259 for (; m != patch_manager.all_models().end(); ++m) {
260 _midnam_model_selector.append_text(m->c_str());
263 if (gui_property (X_("midnam-model-name")).empty()) {
264 set_gui_property (X_("midnam-model-name"), "Generic");
267 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
268 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
270 set_gui_property (X_("midnam-custom-device-mode"),
271 *device_names->custom_device_mode_names().begin());
275 _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
276 _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
278 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
279 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
281 _midi_controls_box.set_homogeneous(false);
282 _midi_controls_box.set_border_width (10);
284 _channel_status_box.set_homogeneous (false);
285 _channel_status_box.set_spacing (6);
287 _channel_selector_button.set_label (_("Chns"));
288 ARDOUR_UI::instance()->set_tip (_channel_selector_button, _("Click to edit channel settings"));
290 /* fixed sized labels to prevent silly nonsense (though obviously,
291 * they cause their own too)
294 _playback_channel_status.set_size_request (65, -1);
295 _capture_channel_status.set_size_request (60, -1);
297 _channel_status_box.pack_start (_playback_channel_status, false, false);
298 _channel_status_box.pack_start (_capture_channel_status, false, false);
299 _channel_status_box.pack_start (_channel_selector_button, false, false);
300 _channel_status_box.show_all ();
302 _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
304 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
306 if (!patch_manager.all_models().empty()) {
308 _midnam_model_selector.set_size_request(22, 30);
309 _midnam_model_selector.set_border_width(2);
310 _midnam_model_selector.show ();
311 _midi_controls_box.pack_start (_midnam_model_selector);
313 _midnam_custom_device_mode_selector.set_size_request(10, 30);
314 _midnam_custom_device_mode_selector.set_border_width(2);
315 _midnam_custom_device_mode_selector.show ();
317 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
321 custom_device_mode_changed();
323 _midnam_model_selector.signal_changed().connect(
324 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
325 _midnam_custom_device_mode_selector.signal_changed().connect(
326 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
328 controls_vbox.pack_start(_midi_controls_box, false, false);
330 const string color_mode = gui_property ("color-mode");
331 if (!color_mode.empty()) {
332 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
333 if (_channel_selector && _color_mode == ChannelColors) {
334 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
338 set_color_mode (_color_mode, true, false);
340 const string note_mode = gui_property ("note-mode");
341 if (!note_mode.empty()) {
342 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
343 if (_percussion_mode_item) {
344 _percussion_mode_item->set_active (_note_mode == Percussive);
348 /* Look for any GUI object state nodes that represent automation children
349 * that should exist, and create the children.
352 const list<string> gui_ids = gui_object_state().all_ids ();
353 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
356 Evoral::Parameter parameter (0, 0, 0);
358 bool const p = AutomationTimeAxisView::parse_state_id (
359 *i, route_id, has_parameter, parameter);
360 if (p && route_id == _route->id () && has_parameter) {
361 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
362 create_automation_child (parameter, string_is_affirmative (visible));
368 MidiTimeAxisView::first_idle ()
375 MidiTimeAxisView::~MidiTimeAxisView ()
377 delete _channel_selector;
379 delete _piano_roll_header;
380 _piano_roll_header = 0;
382 delete _range_scroomer;
385 delete controller_menu;
390 MidiTimeAxisView::enter_internal_edit_mode ()
393 midi_view()->enter_internal_edit_mode ();
398 MidiTimeAxisView::leave_internal_edit_mode ()
401 midi_view()->leave_internal_edit_mode ();
406 MidiTimeAxisView::check_step_edit ()
408 ensure_step_editor ();
409 _step_editor->check_step_edit ();
413 MidiTimeAxisView::model_changed()
415 const Glib::ustring model = _midnam_model_selector.get_active_text();
416 set_gui_property (X_("midnam-model-name"), model);
418 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
419 .custom_device_mode_names_by_model(model);
421 _midnam_custom_device_mode_selector.clear_items();
423 for (std::list<std::string>::const_iterator i = device_modes.begin();
424 i != device_modes.end(); ++i) {
425 _midnam_custom_device_mode_selector.append_text(*i);
428 _midnam_custom_device_mode_selector.set_active(0);
430 _route->instrument_info().set_external_instrument (
431 _midnam_model_selector.get_active_text(),
432 _midnam_custom_device_mode_selector.get_active_text());
434 // Rebuild controller menu
435 _controller_menu_map.clear ();
436 delete controller_menu;
438 build_automation_action_menu(false);
442 MidiTimeAxisView::custom_device_mode_changed()
444 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
445 set_gui_property (X_("midnam-custom-device-mode"), mode);
446 _route->instrument_info().set_external_instrument (
447 _midnam_model_selector.get_active_text(), mode);
451 MidiTimeAxisView::midi_view()
453 return dynamic_cast<MidiStreamView*>(_view);
457 MidiTimeAxisView::set_height (uint32_t h)
459 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
460 _midi_controls_box.show ();
462 _midi_controls_box.hide();
465 if (h >= KEYBOARD_MIN_HEIGHT) {
466 if (is_track() && _range_scroomer) {
467 _range_scroomer->show();
469 if (is_track() && _piano_roll_header) {
470 _piano_roll_header->show();
473 if (is_track() && _range_scroomer) {
474 _range_scroomer->hide();
476 if (is_track() && _piano_roll_header) {
477 _piano_roll_header->hide();
481 /* We need to do this after changing visibility of our stuff, as it will
482 eventually trigger a call to Editor::reset_controls_layout_width(),
483 which needs to know if we have just shown or hidden a scroomer /
486 RouteTimeAxisView::set_height (h);
490 MidiTimeAxisView::append_extra_display_menu_items ()
492 using namespace Menu_Helpers;
494 MenuList& items = display_menu->items();
497 Menu *range_menu = manage(new Menu);
498 MenuList& range_items = range_menu->items();
499 range_menu->set_name ("ArdourContextMenu");
501 range_items.push_back (
502 MenuElem (_("Show Full Range"),
503 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
504 MidiStreamView::FullRange, true)));
506 range_items.push_back (
507 MenuElem (_("Fit Contents"),
508 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
509 MidiStreamView::ContentsRange, true)));
511 items.push_back (MenuElem (_("Note Range"), *range_menu));
512 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
513 items.push_back (MenuElem (_("Channel Selector"),
514 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
516 color_mode_menu = build_color_mode_menu();
517 if (color_mode_menu) {
518 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
521 items.push_back (SeparatorElem ());
525 MidiTimeAxisView::toggle_channel_selector ()
527 if (!_channel_selector) {
528 _channel_selector = new MidiChannelSelectorWindow (midi_track());
530 if (_color_mode == ChannelColors) {
531 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
533 _channel_selector->set_default_channel_color ();
536 _channel_selector->show_all ();
538 _channel_selector->cycle_visibility ();
543 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
545 using namespace Menu_Helpers;
547 /* If we have a controller menu, we need to detach it before
548 RouteTimeAxis::build_automation_action_menu destroys the
549 menu it is attached to. Otherwise GTK destroys
550 controller_menu's gobj, meaning that it can't be reattached
551 below. See bug #3134.
554 if (controller_menu) {
555 detach_menu (*controller_menu);
558 _channel_command_menu_map.clear ();
559 RouteTimeAxisView::build_automation_action_menu (for_selection);
561 MenuList& automation_items = automation_action_menu->items();
563 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
565 if (selected_channels != 0) {
567 automation_items.push_back (SeparatorElem());
569 /* these 2 MIDI "command" types are semantically more like automation
570 than note data, but they are not MIDI controllers. We give them
571 special status in this menu, since they will not show up in the
572 controller list and anyone who actually knows something about MIDI
573 (!) would not expect to find them there.
576 add_channel_command_menu_item (
577 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
578 automation_items.back().set_sensitive (
579 !for_selection || _editor.get_selection().tracks.size() == 1);
580 add_channel_command_menu_item (
581 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
582 automation_items.back().set_sensitive (
583 !for_selection || _editor.get_selection().tracks.size() == 1);
585 /* now all MIDI controllers. Always offer the possibility that we will
586 rebuild the controllers menu since it might need to be updated after
587 a channel mode change or other change. Also detach it first in case
588 it has been used anywhere else.
591 build_controller_menu ();
593 automation_items.push_back (SeparatorElem());
594 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
595 automation_items.back().set_sensitive (
596 !for_selection || _editor.get_selection().tracks.size() == 1);
598 automation_items.push_back (
599 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
600 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
603 automation_items.push_back (SeparatorElem());
604 automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility)));
605 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
606 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
607 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
609 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
611 if (!pan_tracks.empty()) {
612 automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility)));
613 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
614 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
615 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
617 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
618 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
619 _main_automation_menu_map[*p] = pan_automation_item;
626 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
628 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
630 for (uint8_t chn = 0; chn < 16; chn++) {
631 if (selected_channels & (0x0001 << chn)) {
633 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
634 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
637 menu->set_active (yn);
644 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
646 AutomationType auto_type,
649 using namespace Menu_Helpers;
651 /* count the number of selected channels because we will build a different menu
652 structure if there is more than 1 selected.
655 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
658 for (uint8_t chn = 0; chn < 16; chn++) {
659 if (selected_channels & (0x0001 << chn)) {
668 /* multiple channels - create a submenu, with 1 item per channel */
670 Menu* chn_menu = manage (new Menu);
671 MenuList& chn_items (chn_menu->items());
672 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
674 /* add a couple of items to hide/show all of them */
676 chn_items.push_back (
677 MenuElem (_("Hide all channels"),
678 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
679 false, param_without_channel)));
680 chn_items.push_back (
681 MenuElem (_("Show all channels"),
682 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
683 true, param_without_channel)));
685 for (uint8_t chn = 0; chn < 16; chn++) {
686 if (selected_channels & (0x0001 << chn)) {
688 /* for each selected channel, add a menu item for this controller */
690 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
691 chn_items.push_back (
692 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
693 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
694 fully_qualified_param)));
696 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
697 bool visible = false;
700 if (track->marked_for_display()) {
705 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
706 _channel_command_menu_map[fully_qualified_param] = cmi;
707 cmi->set_active (visible);
711 /* now create an item in the parent menu that has the per-channel list as a submenu */
713 items.push_back (MenuElem (label, *chn_menu));
717 /* just one channel - create a single menu item for this command+channel combination*/
719 for (uint8_t chn = 0; chn < 16; chn++) {
720 if (selected_channels & (0x0001 << chn)) {
722 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
724 CheckMenuElem (label,
725 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
726 fully_qualified_param)));
728 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
729 bool visible = false;
732 if (track->marked_for_display()) {
737 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
738 _channel_command_menu_map[fully_qualified_param] = cmi;
739 cmi->set_active (visible);
741 /* one channel only */
748 /** Add a single menu item for a controller on one channel. */
750 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
752 const std::string& name)
754 using namespace Menu_Helpers;
756 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
757 for (uint8_t chn = 0; chn < 16; chn++) {
758 if (selected_channels & (0x0001 << chn)) {
760 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
761 ctl_items.push_back (
763 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
765 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
766 fully_qualified_param)));
767 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
769 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
770 fully_qualified_param);
772 bool visible = false;
774 if (track->marked_for_display()) {
779 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
780 _controller_menu_map[fully_qualified_param] = cmi;
781 cmi->set_active (visible);
783 /* one channel only */
789 /** Add a submenu with 1 item per channel for a controller on many channels. */
791 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
793 const std::string& name)
795 using namespace Menu_Helpers;
797 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
799 Menu* chn_menu = manage (new Menu);
800 MenuList& chn_items (chn_menu->items());
802 /* add a couple of items to hide/show this controller on all channels */
804 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
805 chn_items.push_back (
806 MenuElem (_("Hide all channels"),
807 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
808 false, param_without_channel)));
809 chn_items.push_back (
810 MenuElem (_("Show all channels"),
811 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
812 true, param_without_channel)));
814 for (uint8_t chn = 0; chn < 16; chn++) {
815 if (selected_channels & (0x0001 << chn)) {
817 /* for each selected channel, add a menu item for this controller */
819 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
820 chn_items.push_back (
821 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
822 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
823 fully_qualified_param)));
825 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
826 fully_qualified_param);
827 bool visible = false;
830 if (track->marked_for_display()) {
835 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
836 _controller_menu_map[fully_qualified_param] = cmi;
837 cmi->set_active (visible);
841 /* add the per-channel menu to the list of controllers, with the name of the controller */
842 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
844 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
847 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
848 MidiTimeAxisView::get_device_mode()
850 using namespace MIDI::Name;
852 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
854 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
857 return device_names->custom_device_mode_by_name(
858 gui_property (X_("midnam-custom-device-mode")));
861 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
862 MidiTimeAxisView::get_device_names()
864 using namespace MIDI::Name;
866 const std::string model = gui_property (X_("midnam-model-name"));
868 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
869 .document_by_model(model);
871 return midnam->master_device_names(model);
873 return boost::shared_ptr<MasterDeviceNames>();
878 MidiTimeAxisView::build_controller_menu ()
880 using namespace Menu_Helpers;
882 if (controller_menu) {
883 /* it exists and has not been invalidated by a channel mode change */
887 controller_menu = new Menu; // explicitly managed by us
888 MenuList& items (controller_menu->items());
890 /* create several "top level" menu items for sets of controllers (16 at a
891 time), and populate each one with a submenu for each controller+channel
892 combination covering the currently selected channels for this track
895 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
897 /* count the number of selected channels because we will build a different menu
898 structure if there is more than 1 selected.
902 for (uint8_t chn = 0; chn < 16; chn++) {
903 if (selected_channels & (0x0001 << chn)) {
910 using namespace MIDI::Name;
911 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
913 if (device_names && !device_names->controls().empty()) {
914 /* Controllers names available in midnam file, generate fancy menu */
915 unsigned n_items = 0;
916 unsigned n_groups = 0;
918 /* TODO: This is not correct, should look up the currently applicable ControlNameList
919 and only build a menu for that one. */
920 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
921 l != device_names->controls().end(); ++l) {
922 boost::shared_ptr<ControlNameList> name_list = l->second;
923 Menu* ctl_menu = NULL;
925 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
926 c != name_list->controls().end();) {
927 const uint16_t ctl = c->second->number();
928 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
929 /* Skip bank select controllers since they're handled specially */
931 /* Create a new submenu */
932 ctl_menu = manage (new Menu);
935 MenuList& ctl_items (ctl_menu->items());
937 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
939 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
944 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
945 /* Submenu has 16 items or we're done, add it to controller menu and reset */
947 MenuElem(string_compose(_("Controllers %1-%2"),
948 (16 * n_groups), (16 * n_groups) + n_items - 1),
957 /* No controllers names, generate generic numeric menu */
958 for (int i = 0; i < 127; i += 16) {
959 Menu* ctl_menu = manage (new Menu);
960 MenuList& ctl_items (ctl_menu->items());
962 for (int ctl = i; ctl < i+16; ++ctl) {
963 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
964 /* Skip bank select controllers since they're handled specially */
969 add_multi_channel_controller_item(
970 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
972 add_single_channel_controller_item(
973 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
977 /* Add submenu for this block of controllers to controller menu */
979 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
986 MidiTimeAxisView::build_note_mode_menu()
988 using namespace Menu_Helpers;
990 Menu* mode_menu = manage (new Menu);
991 MenuList& items = mode_menu->items();
992 mode_menu->set_name ("ArdourContextMenu");
994 RadioMenuItem::Group mode_group;
996 RadioMenuElem (mode_group,_("Sustained"),
997 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
999 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1000 _note_mode_item->set_active(_note_mode == Sustained);
1003 RadioMenuElem (mode_group, _("Percussive"),
1004 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1005 Percussive, true)));
1006 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1007 _percussion_mode_item->set_active(_note_mode == Percussive);
1013 MidiTimeAxisView::build_color_mode_menu()
1015 using namespace Menu_Helpers;
1017 Menu* mode_menu = manage (new Menu);
1018 MenuList& items = mode_menu->items();
1019 mode_menu->set_name ("ArdourContextMenu");
1021 RadioMenuItem::Group mode_group;
1023 RadioMenuElem (mode_group, _("Meter Colors"),
1024 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1025 MeterColors, false, true, true)));
1026 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1027 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1030 RadioMenuElem (mode_group, _("Channel Colors"),
1031 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1032 ChannelColors, false, true, true)));
1033 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1034 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1037 RadioMenuElem (mode_group, _("Track Color"),
1038 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1039 TrackColor, false, true, true)));
1040 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1041 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1047 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1049 if (apply_to_selection) {
1050 _editor.get_selection().tracks.foreach_midi_time_axis (
1051 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1053 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1055 midi_track()->set_note_mode(mode);
1056 set_gui_property ("note-mode", enum_2_string(_note_mode));
1057 _view->redisplay_track();
1063 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1065 if (apply_to_selection) {
1066 _editor.get_selection().tracks.foreach_midi_time_axis (
1067 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1069 if (_color_mode == mode && !force) {
1073 if (_channel_selector) {
1074 if (mode == ChannelColors) {
1075 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1077 _channel_selector->set_default_channel_color();
1082 set_gui_property ("color-mode", enum_2_string(_color_mode));
1084 _view->redisplay_track();
1090 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1092 if (apply_to_selection) {
1093 _editor.get_selection().tracks.foreach_midi_time_axis (
1094 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1096 if (!_ignore_signals) {
1097 midi_view()->set_note_range(range);
1103 MidiTimeAxisView::update_range()
1105 MidiGhostRegion* mgr;
1107 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1108 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1109 mgr->update_range();
1115 MidiTimeAxisView::ensure_pan_views (bool show)
1117 bool changed = false;
1118 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1120 (*i)->set_marked_for_display (false);
1123 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1127 if (!_route->panner()) {
1131 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1132 set<Evoral::Parameter>::iterator p;
1134 for (p = params.begin(); p != params.end(); ++p) {
1135 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1137 if (pan_control->parameter().type() == NullAutomation) {
1138 error << "Pan control has NULL automation type!" << endmsg;
1142 if (automation_child (pan_control->parameter ()).get () == 0) {
1144 /* we don't already have an AutomationTimeAxisView for this parameter */
1146 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1148 boost::shared_ptr<AutomationTimeAxisView> t (
1149 new AutomationTimeAxisView (_session,
1153 pan_control->parameter (),
1161 pan_tracks.push_back (t);
1162 add_automation_child (*p, t, show);
1164 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1170 MidiTimeAxisView::update_gain_track_visibility ()
1172 bool const showit = gain_automation_item->get_active();
1174 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1175 gain_track->set_marked_for_display (showit);
1177 /* now trigger a redisplay */
1180 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1186 MidiTimeAxisView::update_pan_track_visibility ()
1188 bool const showit = pan_automation_item->get_active();
1189 bool changed = false;
1191 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1192 if ((*i)->set_marked_for_display (showit)) {
1198 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1203 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1205 using namespace MIDI::Name;
1207 if (apply_to_selection) {
1208 _editor.get_selection().tracks.foreach_midi_time_axis (
1209 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1212 // Show existing automation
1213 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1215 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1216 create_automation_child(*i, true);
1219 // Show automation for all controllers named in midnam file
1220 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1221 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1222 device_names && !device_names->controls().empty()) {
1223 const std::string device_mode = _midnam_custom_device_mode_selector.get_active_text();
1224 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1225 for (uint32_t chn = 0; chn < 16; ++chn) {
1226 if ((selected_channels & (0x0001 << chn)) == 0) {
1227 // Channel not in use
1231 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1237 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1238 chan_names->control_list_name());
1239 if (!control_names) {
1243 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1244 c != control_names->controls().end();
1246 const uint16_t ctl = c->second->number();
1247 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1248 /* Skip bank select controllers since they're handled specially */
1249 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1250 create_automation_child(param, true);
1257 RouteTimeAxisView::show_all_automation ();
1262 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1264 if (apply_to_selection) {
1265 _editor.get_selection().tracks.foreach_midi_time_axis (
1266 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1269 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1271 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1272 create_automation_child (*i, true);
1276 RouteTimeAxisView::show_existing_automation ();
1280 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1283 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1285 if (param.type() == NullAutomation) {
1289 AutomationTracks::iterator existing = _automation_tracks.find (param);
1291 if (existing != _automation_tracks.end()) {
1293 /* automation track created because we had existing data for
1294 * the processor, but visibility may need to be controlled
1295 * since it will have been set visible by default.
1298 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1305 boost::shared_ptr<AutomationTimeAxisView> track;
1307 switch (param.type()) {
1309 case GainAutomation:
1310 create_gain_automation_child (param, show);
1313 case MuteAutomation:
1314 create_mute_automation_child (param, show);
1317 case PluginAutomation:
1318 /* handled elsewhere */
1321 case MidiCCAutomation:
1322 case MidiPgmChangeAutomation:
1323 case MidiPitchBenderAutomation:
1324 case MidiChannelPressureAutomation:
1325 case MidiSystemExclusiveAutomation:
1326 /* These controllers are region "automation" - they are owned
1327 * by regions (and their MidiModels), not by the track. As a
1328 * result we do not create an AutomationList/Line for the track
1329 * ... except here we are doing something!! XXX
1332 track.reset (new AutomationTimeAxisView (
1335 boost::shared_ptr<Automatable> (),
1336 boost::shared_ptr<AutomationControl> (),
1342 _route->describe_parameter(param)));
1345 _view->foreach_regionview (
1346 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1349 add_automation_child (param, track, show);
1352 case PanWidthAutomation:
1353 case PanElevationAutomation:
1354 case PanAzimuthAutomation:
1355 ensure_pan_views (show);
1359 error << "MidiTimeAxisView: unknown automation child "
1360 << EventTypeMap::instance().to_symbol(param) << endmsg;
1365 MidiTimeAxisView::route_active_changed ()
1367 RouteUI::route_active_changed ();
1370 if (_route->active()) {
1371 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1372 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1373 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1375 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1376 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1377 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1380 if (_route->active()) {
1381 controls_ebox.set_name ("BusControlsBaseUnselected");
1382 controls_base_selected_name = "BusControlsBaseSelected";
1383 controls_base_unselected_name = "BusControlsBaseUnselected";
1385 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1386 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1387 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1393 MidiTimeAxisView::set_note_selection (uint8_t note)
1395 if (!_editor.internal_editing()) {
1399 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1401 if (_view->num_selected_regionviews() == 0) {
1402 _view->foreach_regionview (
1403 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1406 _view->foreach_selected_regionview (
1407 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1413 MidiTimeAxisView::add_note_selection (uint8_t note)
1415 if (!_editor.internal_editing()) {
1419 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1421 if (_view->num_selected_regionviews() == 0) {
1422 _view->foreach_regionview (
1423 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1426 _view->foreach_selected_regionview (
1427 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1433 MidiTimeAxisView::extend_note_selection (uint8_t note)
1435 if (!_editor.internal_editing()) {
1439 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1441 if (_view->num_selected_regionviews() == 0) {
1442 _view->foreach_regionview (
1443 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1446 _view->foreach_selected_regionview (
1447 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1453 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1455 if (!_editor.internal_editing()) {
1459 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1461 if (_view->num_selected_regionviews() == 0) {
1462 _view->foreach_regionview (
1463 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1466 _view->foreach_selected_regionview (
1467 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1473 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1475 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1479 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1481 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1485 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1487 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1491 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1493 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1497 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1499 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1503 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1504 bool changed = false;
1508 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1510 for (uint32_t chn = 0; chn < 16; ++chn) {
1511 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1512 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1518 if ((selected_channels & (0x0001 << chn)) == 0) {
1519 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1520 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1522 changed = track->set_marked_for_display (false) || changed;
1524 changed = track->set_marked_for_display (true) || changed;
1531 /* TODO: Bender, Pressure */
1533 /* invalidate the controller menu, so that we rebuild it next time */
1534 _controller_menu_map.clear ();
1535 delete controller_menu;
1536 controller_menu = 0;
1544 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1546 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1551 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1552 if (i != _controller_menu_map.end()) {
1556 i = _channel_command_menu_map.find (param);
1557 if (i != _channel_command_menu_map.end()) {
1564 boost::shared_ptr<MidiRegion>
1565 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1567 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1569 real_editor->begin_reversible_command (Operations::create_region);
1570 playlist()->clear_changes ();
1572 real_editor->snap_to (pos, 0);
1574 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1577 plist.add (ARDOUR::Properties::start, 0);
1578 plist.add (ARDOUR::Properties::length, length);
1579 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1581 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1583 playlist()->add_region (region, pos);
1584 _session->add_command (new StatefulDiffCommand (playlist()));
1587 real_editor->commit_reversible_command ();
1590 return boost::dynamic_pointer_cast<MidiRegion>(region);
1594 MidiTimeAxisView::ensure_step_editor ()
1596 if (!_step_editor) {
1597 _step_editor = new StepEditor (_editor, midi_track(), *this);
1602 MidiTimeAxisView::start_step_editing ()
1604 ensure_step_editor ();
1605 _step_editor->start_step_editing ();
1609 MidiTimeAxisView::stop_step_editing ()
1612 _step_editor->stop_step_editing ();
1616 /** @return channel (counted from 0) to add an event to, based on the current setting
1617 * of the channel selector.
1620 MidiTimeAxisView::get_channel_for_add () const
1622 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1624 uint8_t channel = 0;
1626 /* pick the highest selected channel, unless all channels are selected,
1627 which is interpreted to mean channel 1 (zero)
1630 for (uint16_t i = 0; i < 16; ++i) {
1631 if (chn_mask & (1<<i)) {
1637 if (chn_cnt == 16) {
1645 MidiTimeAxisView::note_range_changed ()
1647 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1648 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1652 MidiTimeAxisView::contents_height_changed ()
1654 _range_scroomer->set_size_request (-1, _view->child_height ());
1658 MidiTimeAxisView::playback_channel_mode_changed ()
1660 switch (midi_track()->get_playback_channel_mode()) {
1662 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1664 case FilterChannels:
1665 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1668 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1674 MidiTimeAxisView::capture_channel_mode_changed ()
1676 switch (midi_track()->get_capture_channel_mode()) {
1678 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1680 case FilterChannels:
1681 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1684 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));