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;
96 using namespace Gtkmm2ext;
97 using namespace Editing;
99 // Minimum height at which a control is displayed
100 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 140;
101 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
103 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
104 : AxisView(sess) // virtually inherited
105 , RouteTimeAxisView(ed, sess, canvas)
106 , _ignore_signals(false)
108 , _piano_roll_header(0)
109 , _note_mode(Sustained)
111 , _percussion_mode_item(0)
112 , _color_mode(MeterColors)
113 , _meter_color_mode_item(0)
114 , _channel_color_mode_item(0)
115 , _track_color_mode_item(0)
116 , _channel_selector (0)
117 , _step_edit_item (0)
118 , controller_menu (0)
124 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
128 _view = new MidiStreamView (*this);
131 _piano_roll_header = new PianoRollHeader(*midi_view());
132 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
133 _range_scroomer->DoubleClicked.connect (
134 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
135 MidiStreamView::ContentsRange, false));
138 /* This next call will result in our height being set up, so it must come after
139 the creation of the piano roll / range scroomer as their visibility is set up
142 RouteTimeAxisView::set_route (rt);
144 _view->apply_color (_color, StreamView::RegionColor);
146 subplugin_menu.set_name ("ArdourContextMenu");
148 if (!gui_property ("note-range-min").empty ()) {
149 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
150 atoi (gui_property ("note-range-max").c_str()),
154 midi_view()->NoteRangeChanged.connect (
155 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
156 _view->ContentsHeightChanged.connect (
157 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
159 ignore_toggle = false;
161 if (is_midi_track()) {
162 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
163 _note_mode = midi_track()->note_mode();
164 } else { // MIDI bus (which doesn't exist yet..)
165 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
168 /* if set_state above didn't create a gain automation child, we need to make one */
169 if (automation_child (GainAutomation) == 0) {
170 create_automation_child (GainAutomation, false);
173 if (_route->panner_shell()) {
174 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
177 /* map current state of the route */
178 ensure_pan_views (false);
180 processors_changed (RouteProcessorChange ());
182 _route->processors_changed.connect (*this, invalidator (*this),
183 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
187 _piano_roll_header->SetNoteSelection.connect (
188 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
189 _piano_roll_header->AddNoteSelection.connect (
190 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
191 _piano_roll_header->ExtendNoteSelection.connect (
192 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
193 _piano_roll_header->ToggleNoteSelection.connect (
194 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
196 /* Suspend updates of the StreamView during scroomer drags to speed things up */
197 _range_scroomer->DragStarting.connect (
198 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
199 _range_scroomer->DragFinishing.connect (
200 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
202 /* Put the scroomer and the keyboard in a VBox with a padding
203 label so that they can be reduced in height for stacked-view
206 VBox* v = manage (new VBox);
207 HBox* h = manage (new HBox);
208 h->pack_start (*_range_scroomer);
209 h->pack_start (*_piano_roll_header);
210 v->pack_start (*h, false, false);
211 v->pack_start (*manage (new Label ("")), true, true);
214 controls_hbox.pack_start(*v, false, false);
216 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
217 controls_base_selected_name = "MidiTrackControlsBaseSelected";
218 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
220 midi_view()->NoteRangeChanged.connect (
221 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
223 /* ask for notifications of any new RegionViews */
224 _view->RegionViewAdded.connect (
225 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
227 midi_track()->PlaybackChannelModeChanged.connect (*this, invalidator (*this),
228 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
230 midi_track()->PlaybackChannelMaskChanged.connect (*this, invalidator (*this),
231 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
233 midi_track()->CaptureChannelModeChanged.connect (*this, invalidator (*this),
234 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
236 midi_track()->CaptureChannelMaskChanged.connect (*this, invalidator (*this),
237 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
240 playback_channel_mode_changed ();
241 capture_channel_mode_changed ();
243 if (!_editor.have_idled()) {
244 /* first idle will do what we need */
250 MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
252 MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
253 for (; m != patch_manager.all_models().end(); ++m) {
254 _midnam_model_selector.append_text(m->c_str());
257 if (gui_property (X_("midnam-model-name")).empty()) {
258 set_gui_property (X_("midnam-model-name"), "Generic");
261 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
262 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
264 set_gui_property (X_("midnam-custom-device-mode"),
265 *device_names->custom_device_mode_names().begin());
269 _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
270 _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
272 ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
273 ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
275 _midi_controls_box.set_homogeneous(false);
276 _midi_controls_box.set_border_width (10);
278 _channel_status_box.set_homogeneous (false);
279 _channel_status_box.set_spacing (6);
281 _channel_selector_button.set_label (_("Chns"));
282 ARDOUR_UI::instance()->set_tip (_channel_selector_button, _("Click to edit channel settings"));
284 /* fixed sized labels to prevent silly nonsense (though obviously,
285 * they cause their own too)
288 _playback_channel_status.set_size_request (65, -1);
289 _capture_channel_status.set_size_request (60, -1);
291 _channel_status_box.pack_start (_playback_channel_status, false, false);
292 _channel_status_box.pack_start (_capture_channel_status, false, false);
293 _channel_status_box.pack_start (_channel_selector_button, false, false);
294 _channel_status_box.show_all ();
296 _channel_selector_button.signal_clicked().connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
298 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
300 if (!patch_manager.all_models().empty()) {
302 _midnam_model_selector.set_size_request(22, 30);
303 _midnam_model_selector.set_border_width(2);
304 _midnam_model_selector.show ();
305 _midi_controls_box.pack_start (_midnam_model_selector);
307 _midnam_custom_device_mode_selector.set_size_request(10, 30);
308 _midnam_custom_device_mode_selector.set_border_width(2);
309 _midnam_custom_device_mode_selector.show ();
311 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector);
315 custom_device_mode_changed();
317 _midnam_model_selector.signal_changed().connect(
318 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
319 _midnam_custom_device_mode_selector.signal_changed().connect(
320 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
322 controls_vbox.pack_start(_midi_controls_box, false, false);
324 const string color_mode = gui_property ("color-mode");
325 if (!color_mode.empty()) {
326 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
327 if (_channel_selector && _color_mode == ChannelColors) {
328 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
332 set_color_mode (_color_mode, true, false);
334 const string note_mode = gui_property ("note-mode");
335 if (!note_mode.empty()) {
336 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
337 if (_percussion_mode_item) {
338 _percussion_mode_item->set_active (_note_mode == Percussive);
342 /* Look for any GUI object state nodes that represent automation children
343 * that should exist, and create the children.
346 const list<string> gui_ids = gui_object_state().all_ids ();
347 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
350 Evoral::Parameter parameter (0, 0, 0);
352 bool const p = AutomationTimeAxisView::parse_state_id (
353 *i, route_id, has_parameter, parameter);
354 if (p && route_id == _route->id () && has_parameter) {
355 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
356 create_automation_child (parameter, string_is_affirmative (visible));
362 MidiTimeAxisView::first_idle ()
369 MidiTimeAxisView::~MidiTimeAxisView ()
371 delete _channel_selector;
373 delete _piano_roll_header;
374 _piano_roll_header = 0;
376 delete _range_scroomer;
379 delete controller_menu;
384 MidiTimeAxisView::enter_internal_edit_mode ()
387 midi_view()->enter_internal_edit_mode ();
392 MidiTimeAxisView::leave_internal_edit_mode ()
395 midi_view()->leave_internal_edit_mode ();
400 MidiTimeAxisView::check_step_edit ()
402 ensure_step_editor ();
403 _step_editor->check_step_edit ();
407 MidiTimeAxisView::model_changed()
409 const Glib::ustring model = _midnam_model_selector.get_active_text();
410 set_gui_property (X_("midnam-model-name"), model);
412 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
413 .custom_device_mode_names_by_model(model);
415 _midnam_custom_device_mode_selector.clear_items();
417 for (std::list<std::string>::const_iterator i = device_modes.begin();
418 i != device_modes.end(); ++i) {
419 _midnam_custom_device_mode_selector.append_text(*i);
422 _midnam_custom_device_mode_selector.set_active(0);
424 _route->instrument_info().set_external_instrument (
425 _midnam_model_selector.get_active_text(),
426 _midnam_custom_device_mode_selector.get_active_text());
428 // Rebuild controller menu
429 _controller_menu_map.clear ();
430 delete controller_menu;
432 build_automation_action_menu(false);
436 MidiTimeAxisView::custom_device_mode_changed()
438 const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
439 set_gui_property (X_("midnam-custom-device-mode"), mode);
440 _route->instrument_info().set_external_instrument (
441 _midnam_model_selector.get_active_text(), mode);
445 MidiTimeAxisView::midi_view()
447 return dynamic_cast<MidiStreamView*>(_view);
451 MidiTimeAxisView::set_height (uint32_t h)
453 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
454 _midi_controls_box.show ();
456 _midi_controls_box.hide();
459 if (h >= KEYBOARD_MIN_HEIGHT) {
460 if (is_track() && _range_scroomer) {
461 _range_scroomer->show();
463 if (is_track() && _piano_roll_header) {
464 _piano_roll_header->show();
467 if (is_track() && _range_scroomer) {
468 _range_scroomer->hide();
470 if (is_track() && _piano_roll_header) {
471 _piano_roll_header->hide();
475 /* We need to do this after changing visibility of our stuff, as it will
476 eventually trigger a call to Editor::reset_controls_layout_width(),
477 which needs to know if we have just shown or hidden a scroomer /
480 RouteTimeAxisView::set_height (h);
484 MidiTimeAxisView::append_extra_display_menu_items ()
486 using namespace Menu_Helpers;
488 MenuList& items = display_menu->items();
491 Menu *range_menu = manage(new Menu);
492 MenuList& range_items = range_menu->items();
493 range_menu->set_name ("ArdourContextMenu");
495 range_items.push_back (
496 MenuElem (_("Show Full Range"),
497 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
498 MidiStreamView::FullRange, true)));
500 range_items.push_back (
501 MenuElem (_("Fit Contents"),
502 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
503 MidiStreamView::ContentsRange, true)));
505 items.push_back (MenuElem (_("Note Range"), *range_menu));
506 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
507 items.push_back (MenuElem (_("Channel Selector"),
508 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
510 color_mode_menu = build_color_mode_menu();
511 if (color_mode_menu) {
512 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
515 items.push_back (SeparatorElem ());
519 MidiTimeAxisView::toggle_channel_selector ()
521 if (!_channel_selector) {
522 _channel_selector = new MidiChannelSelectorWindow (midi_track());
524 if (_color_mode == ChannelColors) {
525 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
527 _channel_selector->set_default_channel_color ();
530 _channel_selector->show_all ();
532 _channel_selector->cycle_visibility ();
537 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
539 using namespace Menu_Helpers;
541 /* If we have a controller menu, we need to detach it before
542 RouteTimeAxis::build_automation_action_menu destroys the
543 menu it is attached to. Otherwise GTK destroys
544 controller_menu's gobj, meaning that it can't be reattached
545 below. See bug #3134.
548 if (controller_menu) {
549 detach_menu (*controller_menu);
552 _channel_command_menu_map.clear ();
553 RouteTimeAxisView::build_automation_action_menu (for_selection);
555 MenuList& automation_items = automation_action_menu->items();
557 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
559 if (selected_channels != 0) {
561 automation_items.push_back (SeparatorElem());
563 /* these 2 MIDI "command" types are semantically more like automation
564 than note data, but they are not MIDI controllers. We give them
565 special status in this menu, since they will not show up in the
566 controller list and anyone who actually knows something about MIDI
567 (!) would not expect to find them there.
570 add_channel_command_menu_item (
571 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
572 automation_items.back().set_sensitive (
573 !for_selection || _editor.get_selection().tracks.size() == 1);
574 add_channel_command_menu_item (
575 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
576 automation_items.back().set_sensitive (
577 !for_selection || _editor.get_selection().tracks.size() == 1);
579 /* now all MIDI controllers. Always offer the possibility that we will
580 rebuild the controllers menu since it might need to be updated after
581 a channel mode change or other change. Also detach it first in case
582 it has been used anywhere else.
585 build_controller_menu ();
587 automation_items.push_back (SeparatorElem());
588 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
589 automation_items.back().set_sensitive (
590 !for_selection || _editor.get_selection().tracks.size() == 1);
592 automation_items.push_back (
593 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
594 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
597 automation_items.push_back (SeparatorElem());
598 automation_items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &MidiTimeAxisView::update_gain_track_visibility)));
599 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
600 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
601 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
603 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
605 if (!pan_tracks.empty()) {
606 automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &MidiTimeAxisView::update_pan_track_visibility)));
607 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&automation_items.back ());
608 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
609 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
611 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
612 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
613 _main_automation_menu_map[*p] = pan_automation_item;
620 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
622 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
624 for (uint8_t chn = 0; chn < 16; chn++) {
625 if (selected_channels & (0x0001 << chn)) {
627 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
628 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
631 menu->set_active (yn);
638 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
640 AutomationType auto_type,
643 using namespace Menu_Helpers;
645 /* count the number of selected channels because we will build a different menu
646 structure if there is more than 1 selected.
649 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
652 for (uint8_t chn = 0; chn < 16; chn++) {
653 if (selected_channels & (0x0001 << chn)) {
662 /* multiple channels - create a submenu, with 1 item per channel */
664 Menu* chn_menu = manage (new Menu);
665 MenuList& chn_items (chn_menu->items());
666 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
668 /* add a couple of items to hide/show all of them */
670 chn_items.push_back (
671 MenuElem (_("Hide all channels"),
672 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
673 false, param_without_channel)));
674 chn_items.push_back (
675 MenuElem (_("Show all channels"),
676 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
677 true, param_without_channel)));
679 for (uint8_t chn = 0; chn < 16; chn++) {
680 if (selected_channels & (0x0001 << chn)) {
682 /* for each selected channel, add a menu item for this controller */
684 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
685 chn_items.push_back (
686 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
687 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
688 fully_qualified_param)));
690 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
691 bool visible = false;
694 if (track->marked_for_display()) {
699 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
700 _channel_command_menu_map[fully_qualified_param] = cmi;
701 cmi->set_active (visible);
705 /* now create an item in the parent menu that has the per-channel list as a submenu */
707 items.push_back (MenuElem (label, *chn_menu));
711 /* just one channel - create a single menu item for this command+channel combination*/
713 for (uint8_t chn = 0; chn < 16; chn++) {
714 if (selected_channels & (0x0001 << chn)) {
716 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
718 CheckMenuElem (label,
719 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
720 fully_qualified_param)));
722 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
723 bool visible = false;
726 if (track->marked_for_display()) {
731 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
732 _channel_command_menu_map[fully_qualified_param] = cmi;
733 cmi->set_active (visible);
735 /* one channel only */
742 /** Add a single menu item for a controller on one channel. */
744 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
746 const std::string& name)
748 using namespace Menu_Helpers;
750 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
751 for (uint8_t chn = 0; chn < 16; chn++) {
752 if (selected_channels & (0x0001 << chn)) {
754 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
755 ctl_items.push_back (
757 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn)),
759 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
760 fully_qualified_param)));
761 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
763 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
764 fully_qualified_param);
766 bool visible = false;
768 if (track->marked_for_display()) {
773 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
774 _controller_menu_map[fully_qualified_param] = cmi;
775 cmi->set_active (visible);
777 /* one channel only */
783 /** Add a submenu with 1 item per channel for a controller on many channels. */
785 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
787 const std::string& name)
789 using namespace Menu_Helpers;
791 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
793 Menu* chn_menu = manage (new Menu);
794 MenuList& chn_items (chn_menu->items());
796 /* add a couple of items to hide/show this controller on all channels */
798 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
799 chn_items.push_back (
800 MenuElem (_("Hide all channels"),
801 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
802 false, param_without_channel)));
803 chn_items.push_back (
804 MenuElem (_("Show all channels"),
805 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
806 true, param_without_channel)));
808 for (uint8_t chn = 0; chn < 16; chn++) {
809 if (selected_channels & (0x0001 << chn)) {
811 /* for each selected channel, add a menu item for this controller */
813 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
814 chn_items.push_back (
815 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
816 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
817 fully_qualified_param)));
819 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
820 fully_qualified_param);
821 bool visible = false;
824 if (track->marked_for_display()) {
829 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
830 _controller_menu_map[fully_qualified_param] = cmi;
831 cmi->set_active (visible);
835 /* add the per-channel menu to the list of controllers, with the name of the controller */
836 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
838 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
841 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
842 MidiTimeAxisView::get_device_mode()
844 using namespace MIDI::Name;
846 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
848 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
851 return device_names->custom_device_mode_by_name(
852 gui_property (X_("midnam-custom-device-mode")));
855 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
856 MidiTimeAxisView::get_device_names()
858 using namespace MIDI::Name;
860 const std::string model = gui_property (X_("midnam-model-name"));
862 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
863 .document_by_model(model);
865 return midnam->master_device_names(model);
867 return boost::shared_ptr<MasterDeviceNames>();
872 MidiTimeAxisView::build_controller_menu ()
874 using namespace Menu_Helpers;
876 if (controller_menu) {
877 /* it exists and has not been invalidated by a channel mode change */
881 controller_menu = new Menu; // explicitly managed by us
882 MenuList& items (controller_menu->items());
884 /* create several "top level" menu items for sets of controllers (16 at a
885 time), and populate each one with a submenu for each controller+channel
886 combination covering the currently selected channels for this track
889 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
891 /* count the number of selected channels because we will build a different menu
892 structure if there is more than 1 selected.
896 for (uint8_t chn = 0; chn < 16; chn++) {
897 if (selected_channels & (0x0001 << chn)) {
904 using namespace MIDI::Name;
905 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
907 if (device_names && !device_names->controls().empty()) {
908 /* Controllers names available in midnam file, generate fancy menu */
909 unsigned n_items = 0;
910 unsigned n_groups = 0;
912 /* TODO: This is not correct, should look up the currently applicable ControlNameList
913 and only build a menu for that one. */
914 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
915 l != device_names->controls().end(); ++l) {
916 boost::shared_ptr<ControlNameList> name_list = l->second;
917 Menu* ctl_menu = NULL;
919 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
920 c != name_list->controls().end();) {
921 const uint16_t ctl = c->second->number();
922 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
923 /* Skip bank select controllers since they're handled specially */
925 /* Create a new submenu */
926 ctl_menu = manage (new Menu);
929 MenuList& ctl_items (ctl_menu->items());
931 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
933 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
938 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
939 /* Submenu has 16 items or we're done, add it to controller menu and reset */
941 MenuElem(string_compose(_("Controllers %1-%2"),
942 (16 * n_groups), (16 * n_groups) + n_items - 1),
951 /* No controllers names, generate generic numeric menu */
952 for (int i = 0; i < 127; i += 16) {
953 Menu* ctl_menu = manage (new Menu);
954 MenuList& ctl_items (ctl_menu->items());
956 for (int ctl = i; ctl < i+16; ++ctl) {
957 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
958 /* Skip bank select controllers since they're handled specially */
963 add_multi_channel_controller_item(
964 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
966 add_single_channel_controller_item(
967 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
971 /* Add submenu for this block of controllers to controller menu */
973 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
980 MidiTimeAxisView::build_note_mode_menu()
982 using namespace Menu_Helpers;
984 Menu* mode_menu = manage (new Menu);
985 MenuList& items = mode_menu->items();
986 mode_menu->set_name ("ArdourContextMenu");
988 RadioMenuItem::Group mode_group;
990 RadioMenuElem (mode_group,_("Sustained"),
991 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
993 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
994 _note_mode_item->set_active(_note_mode == Sustained);
997 RadioMenuElem (mode_group, _("Percussive"),
998 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1000 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1001 _percussion_mode_item->set_active(_note_mode == Percussive);
1007 MidiTimeAxisView::build_color_mode_menu()
1009 using namespace Menu_Helpers;
1011 Menu* mode_menu = manage (new Menu);
1012 MenuList& items = mode_menu->items();
1013 mode_menu->set_name ("ArdourContextMenu");
1015 RadioMenuItem::Group mode_group;
1017 RadioMenuElem (mode_group, _("Meter Colors"),
1018 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1019 MeterColors, false, true, true)));
1020 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1021 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1024 RadioMenuElem (mode_group, _("Channel Colors"),
1025 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1026 ChannelColors, false, true, true)));
1027 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1028 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1031 RadioMenuElem (mode_group, _("Track Color"),
1032 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1033 TrackColor, false, true, true)));
1034 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1035 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1041 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1043 if (apply_to_selection) {
1044 _editor.get_selection().tracks.foreach_midi_time_axis (
1045 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1047 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1049 midi_track()->set_note_mode(mode);
1050 set_gui_property ("note-mode", enum_2_string(_note_mode));
1051 _view->redisplay_track();
1057 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1059 if (apply_to_selection) {
1060 _editor.get_selection().tracks.foreach_midi_time_axis (
1061 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1063 if (_color_mode == mode && !force) {
1067 if (_channel_selector) {
1068 if (mode == ChannelColors) {
1069 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1071 _channel_selector->set_default_channel_color();
1076 set_gui_property ("color-mode", enum_2_string(_color_mode));
1078 _view->redisplay_track();
1084 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1086 if (apply_to_selection) {
1087 _editor.get_selection().tracks.foreach_midi_time_axis (
1088 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1090 if (!_ignore_signals) {
1091 midi_view()->set_note_range(range);
1097 MidiTimeAxisView::update_range()
1099 MidiGhostRegion* mgr;
1101 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1102 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1103 mgr->update_range();
1109 MidiTimeAxisView::ensure_pan_views (bool show)
1111 bool changed = false;
1112 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1114 (*i)->set_marked_for_display (false);
1117 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1121 if (!_route->panner()) {
1125 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1126 set<Evoral::Parameter>::iterator p;
1128 for (p = params.begin(); p != params.end(); ++p) {
1129 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1131 if (pan_control->parameter().type() == NullAutomation) {
1132 error << "Pan control has NULL automation type!" << endmsg;
1136 if (automation_child (pan_control->parameter ()).get () == 0) {
1138 /* we don't already have an AutomationTimeAxisView for this parameter */
1140 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1142 boost::shared_ptr<AutomationTimeAxisView> t (
1143 new AutomationTimeAxisView (_session,
1147 pan_control->parameter (),
1155 pan_tracks.push_back (t);
1156 add_automation_child (*p, t, show);
1158 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1164 MidiTimeAxisView::update_gain_track_visibility ()
1166 bool const showit = gain_automation_item->get_active();
1168 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1169 gain_track->set_marked_for_display (showit);
1171 /* now trigger a redisplay */
1174 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1180 MidiTimeAxisView::update_pan_track_visibility ()
1182 bool const showit = pan_automation_item->get_active();
1183 bool changed = false;
1185 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1186 if ((*i)->set_marked_for_display (showit)) {
1192 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1197 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1199 if (apply_to_selection) {
1200 _editor.get_selection().tracks.foreach_midi_time_axis (
1201 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1204 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1206 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1207 create_automation_child(*i, true);
1211 RouteTimeAxisView::show_all_automation ();
1216 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1218 if (apply_to_selection) {
1219 _editor.get_selection().tracks.foreach_midi_time_axis (
1220 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1223 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1225 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1226 create_automation_child (*i, true);
1230 RouteTimeAxisView::show_existing_automation ();
1234 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1237 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1239 if (param.type() == NullAutomation) {
1243 AutomationTracks::iterator existing = _automation_tracks.find (param);
1245 if (existing != _automation_tracks.end()) {
1247 /* automation track created because we had existing data for
1248 * the processor, but visibility may need to be controlled
1249 * since it will have been set visible by default.
1252 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1259 boost::shared_ptr<AutomationTimeAxisView> track;
1261 switch (param.type()) {
1263 case GainAutomation:
1264 create_gain_automation_child (param, show);
1267 case PluginAutomation:
1268 /* handled elsewhere */
1271 case MidiCCAutomation:
1272 case MidiPgmChangeAutomation:
1273 case MidiPitchBenderAutomation:
1274 case MidiChannelPressureAutomation:
1275 case MidiSystemExclusiveAutomation:
1276 /* These controllers are region "automation" - they are owned
1277 * by regions (and their MidiModels), not by the track. As a
1278 * result we do not create an AutomationList/Line for the track
1279 * ... except here we are doing something!! XXX
1282 track.reset (new AutomationTimeAxisView (
1285 boost::shared_ptr<Automatable> (),
1286 boost::shared_ptr<AutomationControl> (),
1292 _route->describe_parameter(param)));
1295 _view->foreach_regionview (
1296 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1299 add_automation_child (param, track, show);
1302 case PanWidthAutomation:
1303 case PanElevationAutomation:
1304 case PanAzimuthAutomation:
1305 ensure_pan_views (show);
1309 error << "MidiTimeAxisView: unknown automation child "
1310 << EventTypeMap::instance().to_symbol(param) << endmsg;
1315 MidiTimeAxisView::route_active_changed ()
1317 RouteUI::route_active_changed ();
1320 if (_route->active()) {
1321 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1322 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1323 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1325 controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1326 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1327 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1330 if (_route->active()) {
1331 controls_ebox.set_name ("BusControlsBaseUnselected");
1332 controls_base_selected_name = "BusControlsBaseSelected";
1333 controls_base_unselected_name = "BusControlsBaseUnselected";
1335 controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1336 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1337 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1343 MidiTimeAxisView::set_note_selection (uint8_t note)
1345 if (!_editor.internal_editing()) {
1349 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1351 if (_view->num_selected_regionviews() == 0) {
1352 _view->foreach_regionview (
1353 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1356 _view->foreach_selected_regionview (
1357 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1363 MidiTimeAxisView::add_note_selection (uint8_t note)
1365 if (!_editor.internal_editing()) {
1369 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1371 if (_view->num_selected_regionviews() == 0) {
1372 _view->foreach_regionview (
1373 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1376 _view->foreach_selected_regionview (
1377 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1383 MidiTimeAxisView::extend_note_selection (uint8_t note)
1385 if (!_editor.internal_editing()) {
1389 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1391 if (_view->num_selected_regionviews() == 0) {
1392 _view->foreach_regionview (
1393 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1396 _view->foreach_selected_regionview (
1397 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1403 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1405 if (!_editor.internal_editing()) {
1409 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1411 if (_view->num_selected_regionviews() == 0) {
1412 _view->foreach_regionview (
1413 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1416 _view->foreach_selected_regionview (
1417 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1423 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1425 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1429 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1431 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1435 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1437 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1441 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1443 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1447 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1449 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1453 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1454 bool changed = false;
1458 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1460 for (uint32_t chn = 0; chn < 16; ++chn) {
1461 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1462 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1468 if ((selected_channels & (0x0001 << chn)) == 0) {
1469 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1470 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1472 changed = track->set_marked_for_display (false) || changed;
1474 changed = track->set_marked_for_display (true) || changed;
1481 /* TODO: Bender, Pressure */
1483 /* invalidate the controller menu, so that we rebuild it next time */
1484 _controller_menu_map.clear ();
1485 delete controller_menu;
1486 controller_menu = 0;
1494 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1496 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1501 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1502 if (i != _controller_menu_map.end()) {
1506 i = _channel_command_menu_map.find (param);
1507 if (i != _channel_command_menu_map.end()) {
1514 boost::shared_ptr<MidiRegion>
1515 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1517 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1519 real_editor->begin_reversible_command (Operations::create_region);
1520 playlist()->clear_changes ();
1522 real_editor->snap_to (pos, 0);
1524 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1527 plist.add (ARDOUR::Properties::start, 0);
1528 plist.add (ARDOUR::Properties::length, length);
1529 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1531 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1533 playlist()->add_region (region, pos);
1534 _session->add_command (new StatefulDiffCommand (playlist()));
1537 real_editor->commit_reversible_command ();
1540 return boost::dynamic_pointer_cast<MidiRegion>(region);
1544 MidiTimeAxisView::ensure_step_editor ()
1546 if (!_step_editor) {
1547 _step_editor = new StepEditor (_editor, midi_track(), *this);
1552 MidiTimeAxisView::start_step_editing ()
1554 ensure_step_editor ();
1555 _step_editor->start_step_editing ();
1559 MidiTimeAxisView::stop_step_editing ()
1562 _step_editor->stop_step_editing ();
1566 /** @return channel (counted from 0) to add an event to, based on the current setting
1567 * of the channel selector.
1570 MidiTimeAxisView::get_channel_for_add () const
1572 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1574 uint8_t channel = 0;
1576 /* pick the highest selected channel, unless all channels are selected,
1577 which is interpreted to mean channel 1 (zero)
1580 for (uint16_t i = 0; i < 16; ++i) {
1581 if (chn_mask & (1<<i)) {
1587 if (chn_cnt == 16) {
1595 MidiTimeAxisView::note_range_changed ()
1597 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1598 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1602 MidiTimeAxisView::contents_height_changed ()
1604 _range_scroomer->set_size_request (-1, _view->child_height ());
1608 MidiTimeAxisView::playback_channel_mode_changed ()
1610 switch (midi_track()->get_playback_channel_mode()) {
1612 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1614 case FilterChannels:
1615 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1618 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1624 MidiTimeAxisView::capture_channel_mode_changed ()
1626 switch (midi_track()->get_capture_channel_mode()) {
1628 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1630 case FilterChannels:
1631 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1634 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));