2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
28 #include "pbd/error.h"
30 #include "pbd/stl_delete.h"
31 #include "pbd/whitespace.h"
32 #include "pbd/basename.h"
33 #include "pbd/enumwriter.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/stateful_diff_command.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/selector.h"
39 #include "gtkmm2ext/bindable_button.h"
40 #include "gtkmm2ext/utils.h"
42 #include "ardour/event_type_map.h"
43 #include "ardour/midi_patch_manager.h"
44 #include "ardour/midi_playlist.h"
45 #include "ardour/midi_region.h"
46 #include "ardour/midi_source.h"
47 #include "ardour/midi_track.h"
48 #include "ardour/operations.h"
49 #include "ardour/pannable.h"
50 #include "ardour/panner.h"
51 #include "ardour/panner_shell.h"
52 #include "ardour/playlist.h"
53 #include "ardour/profile.h"
54 #include "ardour/region.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/route.h"
57 #include "ardour/session.h"
58 #include "ardour/session_object.h"
59 #include "ardour/source.h"
60 #include "ardour/track.h"
61 #include "ardour/types.h"
63 #include "ardour_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"
88 #include "note_base.h"
90 #include "ardour/midi_track.h"
94 using namespace ARDOUR;
95 using namespace ARDOUR_UI_UTILS;
98 using namespace Gtkmm2ext;
99 using namespace Editing;
102 // Minimum height at which a control is displayed
103 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
104 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
106 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
107 : SessionHandlePtr (sess)
108 , RouteTimeAxisView (ed, sess, canvas)
109 , _ignore_signals(false)
111 , _piano_roll_header(0)
112 , _note_mode(Sustained)
114 , _percussion_mode_item(0)
115 , _color_mode(MeterColors)
116 , _meter_color_mode_item(0)
117 , _channel_color_mode_item(0)
118 , _track_color_mode_item(0)
119 , _channel_selector (0)
120 , _step_edit_item (0)
121 , controller_menu (0)
124 _midnam_model_selector.disable_scrolling();
125 _midnam_custom_device_mode_selector.disable_scrolling();
129 MidiTimeAxisView::set_note_highlight (uint8_t note) {
130 _piano_roll_header->set_note_highlight (note);
134 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
138 _view = new MidiStreamView (*this);
141 _piano_roll_header = new PianoRollHeader(*midi_view());
142 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
143 _range_scroomer->DoubleClicked.connect (
144 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
145 MidiStreamView::ContentsRange, false));
148 /* This next call will result in our height being set up, so it must come after
149 the creation of the piano roll / range scroomer as their visibility is set up
152 RouteTimeAxisView::set_route (rt);
154 _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
156 subplugin_menu.set_name ("ArdourContextMenu");
158 if (!gui_property ("note-range-min").empty ()) {
159 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
160 atoi (gui_property ("note-range-max").c_str()),
164 midi_view()->NoteRangeChanged.connect (
165 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
166 _view->ContentsHeightChanged.connect (
167 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
169 ignore_toggle = false;
171 if (is_midi_track()) {
172 _note_mode = midi_track()->note_mode();
175 /* if set_state above didn't create a gain automation child, we need to make one */
176 if (automation_child (GainAutomation) == 0) {
177 create_automation_child (GainAutomation, false);
180 /* if set_state above didn't create a mute automation child, we need to make one */
181 if (automation_child (MuteAutomation) == 0) {
182 create_automation_child (MuteAutomation, false);
185 if (_route->panner_shell()) {
186 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
189 /* map current state of the route */
190 ensure_pan_views (false);
191 update_control_names();
192 processors_changed (RouteProcessorChange ());
194 _route->processors_changed.connect (*this, invalidator (*this),
195 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
199 _piano_roll_header->SetNoteSelection.connect (
200 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
201 _piano_roll_header->AddNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
203 _piano_roll_header->ExtendNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
205 _piano_roll_header->ToggleNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
208 /* Suspend updates of the StreamView during scroomer drags to speed things up */
209 _range_scroomer->DragStarting.connect (
210 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
211 _range_scroomer->DragFinishing.connect (
212 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
214 /* Put the scroomer and the keyboard in a VBox with a padding
215 label so that they can be reduced in height for stacked-view
219 HSeparator* separator = manage (new HSeparator());
220 separator->set_name("TrackSeparator");
221 separator->set_size_request(-1, 1);
224 VBox* v = manage (new VBox);
225 HBox* h = manage (new HBox);
226 h->pack_end (*_piano_roll_header);
227 h->pack_end (*_range_scroomer);
228 v->pack_start (*separator, false, false);
229 v->pack_start (*h, true, true);
232 top_hbox.remove(scroomer_placeholder);
233 time_axis_hbox.pack_end(*v, false, false, 0);
234 midi_scroomer_size_group->add_widget (*v);
236 midi_view()->NoteRangeChanged.connect (
237 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
239 /* ask for notifications of any new RegionViews */
240 _view->RegionViewAdded.connect (
241 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
243 midi_track()->playback_filter().ChannelModeChanged.connect (
244 *this, invalidator (*this),
245 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
247 midi_track()->playback_filter().ChannelMaskChanged.connect (
248 *this, invalidator (*this),
249 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
251 midi_track()->capture_filter().ChannelModeChanged.connect (
252 *this, invalidator (*this),
253 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
255 midi_track()->capture_filter().ChannelMaskChanged.connect (
256 *this, invalidator (*this),
257 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
260 playback_channel_mode_changed ();
261 capture_channel_mode_changed ();
263 if (!_editor.have_idled()) {
264 /* first idle will do what we need */
270 typedef MIDI::Name::MidiPatchManager PatchManager;
272 PatchManager& patch_manager = PatchManager::instance();
274 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
275 m != patch_manager.devices_by_manufacturer().end(); ++m) {
276 Menu* menu = Gtk::manage(new Menu);
277 Menu_Helpers::MenuList& items = menu->items();
279 // Build manufacturer submenu
280 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
281 n != m->second.end(); ++n) {
282 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
284 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
287 items.push_back(elem);
290 // Add manufacturer submenu to selector
291 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
294 if (gui_property (X_("midnam-model-name")).empty()) {
295 set_gui_property (X_("midnam-model-name"), "Generic");
298 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
299 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
301 set_gui_property (X_("midnam-custom-device-mode"),
302 *device_names->custom_device_mode_names().begin());
306 set_tooltip (_midnam_model_selector, _("External MIDI Device"));
307 set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
309 _midi_controls_box.set_homogeneous(false);
310 _midi_controls_box.set_border_width (2);
312 _channel_status_box.set_homogeneous (false);
313 _channel_status_box.set_spacing (4);
315 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
316 channel_selector_button->set_name ("route button");
317 set_tooltip (channel_selector_button, _("Click to edit channel settings"));
319 // Insert expanding space labels to get full width justification
320 _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
321 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
322 _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
323 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
324 _channel_status_box.pack_end (*channel_selector_button, false, false);
325 _channel_status_box.show_all ();
327 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
329 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
331 if (!patch_manager.all_models().empty()) {
333 _midnam_model_selector.show ();
334 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
336 _midnam_custom_device_mode_selector.show ();
338 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
341 model_changed(gui_property(X_("midnam-model-name")));
342 custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
344 controls_vbox.pack_start(_midi_controls_box, false, false);
346 const string color_mode = gui_property ("color-mode");
347 if (!color_mode.empty()) {
348 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
349 if (_channel_selector && _color_mode == ChannelColors) {
350 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
354 set_color_mode (_color_mode, true, false);
356 const string note_mode = gui_property ("note-mode");
357 if (!note_mode.empty()) {
358 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
359 if (_percussion_mode_item) {
360 _percussion_mode_item->set_active (_note_mode == Percussive);
364 /* Look for any GUI object state nodes that represent automation children
365 * that should exist, and create the children.
368 const list<string> gui_ids = gui_object_state().all_ids ();
369 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
372 Evoral::Parameter parameter (0, 0, 0);
374 bool const p = AutomationTimeAxisView::parse_state_id (
375 *i, route_id, has_parameter, parameter);
376 if (p && route_id == _route->id () && has_parameter) {
377 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
378 create_automation_child (parameter, string_is_affirmative (visible));
384 MidiTimeAxisView::first_idle ()
391 MidiTimeAxisView::~MidiTimeAxisView ()
393 delete _channel_selector;
395 delete _piano_roll_header;
396 _piano_roll_header = 0;
398 delete _range_scroomer;
401 delete controller_menu;
406 MidiTimeAxisView::check_step_edit ()
408 ensure_step_editor ();
409 _step_editor->check_step_edit ();
413 MidiTimeAxisView::model_changed(const std::string& model)
415 set_gui_property (X_("midnam-model-name"), model);
417 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
418 .custom_device_mode_names_by_model(model);
420 _midnam_model_selector.set_text(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.AddMenuElem(
426 Gtk::Menu_Helpers::MenuElem(
427 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
431 if (!device_modes.empty()) {
432 custom_device_mode_changed(device_modes.front());
435 if (device_modes.size() > 1) {
436 _midnam_custom_device_mode_selector.show();
438 _midnam_custom_device_mode_selector.hide();
441 if (device_modes.size() > 0) {
442 _route->instrument_info().set_external_instrument (model, device_modes.front());
444 _route->instrument_info().set_external_instrument (model, "");
447 // Rebuild controller menu
448 _controller_menu_map.clear ();
449 delete controller_menu;
451 build_automation_action_menu(false);
455 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
457 const std::string model = gui_property (X_("midnam-model-name"));
459 set_gui_property (X_("midnam-custom-device-mode"), mode);
460 _midnam_custom_device_mode_selector.set_text(mode);
461 _route->instrument_info().set_external_instrument (model, mode);
465 MidiTimeAxisView::midi_view()
467 return dynamic_cast<MidiStreamView*>(_view);
471 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
473 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
474 _midi_controls_box.show ();
476 _midi_controls_box.hide();
479 if (h >= KEYBOARD_MIN_HEIGHT) {
480 if (is_track() && _range_scroomer) {
481 _range_scroomer->show();
483 if (is_track() && _piano_roll_header) {
484 _piano_roll_header->show();
487 if (is_track() && _range_scroomer) {
488 _range_scroomer->hide();
490 if (is_track() && _piano_roll_header) {
491 _piano_roll_header->hide();
495 /* We need to do this after changing visibility of our stuff, as it will
496 eventually trigger a call to Editor::reset_controls_layout_width(),
497 which needs to know if we have just shown or hidden a scroomer /
500 RouteTimeAxisView::set_height (h, m);
504 MidiTimeAxisView::append_extra_display_menu_items ()
506 using namespace Menu_Helpers;
508 MenuList& items = display_menu->items();
511 Menu *range_menu = manage(new Menu);
512 MenuList& range_items = range_menu->items();
513 range_menu->set_name ("ArdourContextMenu");
515 range_items.push_back (
516 MenuElem (_("Show Full Range"),
517 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
518 MidiStreamView::FullRange, true)));
520 range_items.push_back (
521 MenuElem (_("Fit Contents"),
522 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
523 MidiStreamView::ContentsRange, true)));
525 items.push_back (MenuElem (_("Note Range"), *range_menu));
526 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
527 items.push_back (MenuElem (_("Channel Selector"),
528 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
530 color_mode_menu = build_color_mode_menu();
531 if (color_mode_menu) {
532 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
535 items.push_back (SeparatorElem ());
539 MidiTimeAxisView::toggle_channel_selector ()
541 if (!_channel_selector) {
542 _channel_selector = new MidiChannelSelectorWindow (midi_track());
544 if (_color_mode == ChannelColors) {
545 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
547 _channel_selector->set_default_channel_color ();
550 _channel_selector->show_all ();
552 _channel_selector->cycle_visibility ();
557 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
559 using namespace Menu_Helpers;
561 /* If we have a controller menu, we need to detach it before
562 RouteTimeAxis::build_automation_action_menu destroys the
563 menu it is attached to. Otherwise GTK destroys
564 controller_menu's gobj, meaning that it can't be reattached
565 below. See bug #3134.
568 if (controller_menu) {
569 detach_menu (*controller_menu);
572 _channel_command_menu_map.clear ();
573 RouteTimeAxisView::build_automation_action_menu (for_selection);
575 MenuList& automation_items = automation_action_menu->items();
577 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
579 if (selected_channels != 0) {
581 automation_items.push_back (SeparatorElem());
583 /* these 2 MIDI "command" types are semantically more like automation
584 than note data, but they are not MIDI controllers. We give them
585 special status in this menu, since they will not show up in the
586 controller list and anyone who actually knows something about MIDI
587 (!) would not expect to find them there.
590 add_channel_command_menu_item (
591 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
592 automation_items.back().set_sensitive (
593 !for_selection || _editor.get_selection().tracks.size() == 1);
594 add_channel_command_menu_item (
595 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
596 automation_items.back().set_sensitive (
597 !for_selection || _editor.get_selection().tracks.size() == 1);
599 /* now all MIDI controllers. Always offer the possibility that we will
600 rebuild the controllers menu since it might need to be updated after
601 a channel mode change or other change. Also detach it first in case
602 it has been used anywhere else.
605 build_controller_menu ();
607 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
608 automation_items.back().set_sensitive (
609 !for_selection || _editor.get_selection().tracks.size() == 1);
611 automation_items.push_back (
612 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
613 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
618 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
620 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
622 for (uint8_t chn = 0; chn < 16; chn++) {
623 if (selected_channels & (0x0001 << chn)) {
625 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
626 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
629 menu->set_active (yn);
636 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
638 AutomationType auto_type,
641 using namespace Menu_Helpers;
643 /* count the number of selected channels because we will build a different menu
644 structure if there is more than 1 selected.
647 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
650 for (uint8_t chn = 0; chn < 16; chn++) {
651 if (selected_channels & (0x0001 << chn)) {
660 /* multiple channels - create a submenu, with 1 item per channel */
662 Menu* chn_menu = manage (new Menu);
663 MenuList& chn_items (chn_menu->items());
664 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
666 /* add a couple of items to hide/show all of them */
668 chn_items.push_back (
669 MenuElem (_("Hide all channels"),
670 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
671 false, param_without_channel)));
672 chn_items.push_back (
673 MenuElem (_("Show all channels"),
674 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
675 true, param_without_channel)));
677 for (uint8_t chn = 0; chn < 16; chn++) {
678 if (selected_channels & (0x0001 << chn)) {
680 /* for each selected channel, add a menu item for this controller */
682 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
683 chn_items.push_back (
684 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
685 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
686 fully_qualified_param)));
688 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
689 bool visible = false;
692 if (track->marked_for_display()) {
697 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
698 _channel_command_menu_map[fully_qualified_param] = cmi;
699 cmi->set_active (visible);
703 /* now create an item in the parent menu that has the per-channel list as a submenu */
705 items.push_back (MenuElem (label, *chn_menu));
709 /* just one channel - create a single menu item for this command+channel combination*/
711 for (uint8_t chn = 0; chn < 16; chn++) {
712 if (selected_channels & (0x0001 << chn)) {
714 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
716 CheckMenuElem (label,
717 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
718 fully_qualified_param)));
720 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
721 bool visible = false;
724 if (track->marked_for_display()) {
729 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
730 _channel_command_menu_map[fully_qualified_param] = cmi;
731 cmi->set_active (visible);
733 /* one channel only */
740 /** Add a single menu item for a controller on one channel. */
742 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
744 const std::string& name)
746 using namespace Menu_Helpers;
748 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
749 for (uint8_t chn = 0; chn < 16; chn++) {
750 if (selected_channels & (0x0001 << chn)) {
752 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
753 ctl_items.push_back (
755 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
757 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
758 fully_qualified_param)));
759 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
761 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
762 fully_qualified_param);
764 bool visible = false;
766 if (track->marked_for_display()) {
771 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
772 _controller_menu_map[fully_qualified_param] = cmi;
773 cmi->set_active (visible);
775 /* one channel only */
781 /** Add a submenu with 1 item per channel for a controller on many channels. */
783 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
785 const std::string& name)
787 using namespace Menu_Helpers;
789 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
791 Menu* chn_menu = manage (new Menu);
792 MenuList& chn_items (chn_menu->items());
794 /* add a couple of items to hide/show this controller on all channels */
796 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
797 chn_items.push_back (
798 MenuElem (_("Hide all channels"),
799 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
800 false, param_without_channel)));
801 chn_items.push_back (
802 MenuElem (_("Show all channels"),
803 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
804 true, param_without_channel)));
806 for (uint8_t chn = 0; chn < 16; chn++) {
807 if (selected_channels & (0x0001 << chn)) {
809 /* for each selected channel, add a menu item for this controller */
811 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
812 chn_items.push_back (
813 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
814 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
815 fully_qualified_param)));
817 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
818 fully_qualified_param);
819 bool visible = false;
822 if (track->marked_for_display()) {
827 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
828 _controller_menu_map[fully_qualified_param] = cmi;
829 cmi->set_active (visible);
833 /* add the per-channel menu to the list of controllers, with the name of the controller */
834 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
836 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
839 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
840 MidiTimeAxisView::get_device_mode()
842 using namespace MIDI::Name;
844 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
846 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
849 return device_names->custom_device_mode_by_name(
850 gui_property (X_("midnam-custom-device-mode")));
853 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
854 MidiTimeAxisView::get_device_names()
856 using namespace MIDI::Name;
858 const std::string model = gui_property (X_("midnam-model-name"));
860 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
861 .document_by_model(model);
863 return midnam->master_device_names(model);
865 return boost::shared_ptr<MasterDeviceNames>();
870 MidiTimeAxisView::build_controller_menu ()
872 using namespace Menu_Helpers;
874 if (controller_menu) {
875 /* it exists and has not been invalidated by a channel mode change */
879 controller_menu = new Menu; // explicitly managed by us
880 MenuList& items (controller_menu->items());
882 /* create several "top level" menu items for sets of controllers (16 at a
883 time), and populate each one with a submenu for each controller+channel
884 combination covering the currently selected channels for this track
887 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
889 /* count the number of selected channels because we will build a different menu
890 structure if there is more than 1 selected.
894 for (uint8_t chn = 0; chn < 16; chn++) {
895 if (selected_channels & (0x0001 << chn)) {
902 using namespace MIDI::Name;
903 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
905 if (device_names && !device_names->controls().empty()) {
906 /* Controllers names available in midnam file, generate fancy menu */
907 unsigned n_items = 0;
908 unsigned n_groups = 0;
910 /* TODO: This is not correct, should look up the currently applicable ControlNameList
911 and only build a menu for that one. */
912 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
913 l != device_names->controls().end(); ++l) {
914 boost::shared_ptr<ControlNameList> name_list = l->second;
915 Menu* ctl_menu = NULL;
917 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
918 c != name_list->controls().end();) {
919 const uint16_t ctl = c->second->number();
920 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
921 /* Skip bank select controllers since they're handled specially */
923 /* Create a new submenu */
924 ctl_menu = manage (new Menu);
927 MenuList& ctl_items (ctl_menu->items());
929 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
931 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
936 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
937 /* Submenu has 16 items or we're done, add it to controller menu and reset */
939 MenuElem(string_compose(_("Controllers %1-%2"),
940 (16 * n_groups), (16 * n_groups) + n_items - 1),
949 /* No controllers names, generate generic numeric menu */
950 for (int i = 0; i < 127; i += 16) {
951 Menu* ctl_menu = manage (new Menu);
952 MenuList& ctl_items (ctl_menu->items());
954 for (int ctl = i; ctl < i+16; ++ctl) {
955 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
956 /* Skip bank select controllers since they're handled specially */
961 add_multi_channel_controller_item(
962 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
964 add_single_channel_controller_item(
965 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
969 /* Add submenu for this block of controllers to controller menu */
971 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
978 MidiTimeAxisView::build_note_mode_menu()
980 using namespace Menu_Helpers;
982 Menu* mode_menu = manage (new Menu);
983 MenuList& items = mode_menu->items();
984 mode_menu->set_name ("ArdourContextMenu");
986 RadioMenuItem::Group mode_group;
988 RadioMenuElem (mode_group,_("Sustained"),
989 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
991 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
992 _note_mode_item->set_active(_note_mode == Sustained);
995 RadioMenuElem (mode_group, _("Percussive"),
996 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
998 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
999 _percussion_mode_item->set_active(_note_mode == Percussive);
1005 MidiTimeAxisView::build_color_mode_menu()
1007 using namespace Menu_Helpers;
1009 Menu* mode_menu = manage (new Menu);
1010 MenuList& items = mode_menu->items();
1011 mode_menu->set_name ("ArdourContextMenu");
1013 RadioMenuItem::Group mode_group;
1015 RadioMenuElem (mode_group, _("Meter Colors"),
1016 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1017 MeterColors, false, true, true)));
1018 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1019 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1022 RadioMenuElem (mode_group, _("Channel Colors"),
1023 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1024 ChannelColors, false, true, true)));
1025 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1026 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1029 RadioMenuElem (mode_group, _("Track Color"),
1030 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1031 TrackColor, false, true, true)));
1032 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1033 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1039 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1041 if (apply_to_selection) {
1042 _editor.get_selection().tracks.foreach_midi_time_axis (
1043 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1045 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1047 midi_track()->set_note_mode(mode);
1048 set_gui_property ("note-mode", enum_2_string(_note_mode));
1049 _view->redisplay_track();
1055 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1057 if (apply_to_selection) {
1058 _editor.get_selection().tracks.foreach_midi_time_axis (
1059 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1061 if (_color_mode == mode && !force) {
1065 if (_channel_selector) {
1066 if (mode == ChannelColors) {
1067 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1069 _channel_selector->set_default_channel_color();
1074 set_gui_property ("color-mode", enum_2_string(_color_mode));
1076 _view->redisplay_track();
1082 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1084 if (apply_to_selection) {
1085 _editor.get_selection().tracks.foreach_midi_time_axis (
1086 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1088 if (!_ignore_signals) {
1089 midi_view()->set_note_range(range);
1095 MidiTimeAxisView::update_range()
1097 MidiGhostRegion* mgr;
1099 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1100 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1101 mgr->update_range();
1107 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1109 using namespace MIDI::Name;
1111 if (apply_to_selection) {
1112 _editor.get_selection().tracks.foreach_midi_time_axis (
1113 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1116 // Show existing automation
1117 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1119 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1120 create_automation_child(*i, true);
1123 // Show automation for all controllers named in midnam file
1124 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1125 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1126 device_names && !device_names->controls().empty()) {
1127 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1128 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1129 for (uint32_t chn = 0; chn < 16; ++chn) {
1130 if ((selected_channels & (0x0001 << chn)) == 0) {
1131 // Channel not in use
1135 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1141 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1142 chan_names->control_list_name());
1143 if (!control_names) {
1147 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1148 c != control_names->controls().end();
1150 const uint16_t ctl = c->second->number();
1151 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1152 /* Skip bank select controllers since they're handled specially */
1153 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1154 create_automation_child(param, true);
1161 RouteTimeAxisView::show_all_automation ();
1166 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1168 if (apply_to_selection) {
1169 _editor.get_selection().tracks.foreach_midi_time_axis (
1170 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1173 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1175 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1176 create_automation_child (*i, true);
1180 RouteTimeAxisView::show_existing_automation ();
1184 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1187 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1189 if (param.type() == NullAutomation) {
1193 AutomationTracks::iterator existing = _automation_tracks.find (param);
1195 if (existing != _automation_tracks.end()) {
1197 /* automation track created because we had existing data for
1198 * the processor, but visibility may need to be controlled
1199 * since it will have been set visible by default.
1202 existing->second->set_marked_for_display (show);
1211 boost::shared_ptr<AutomationTimeAxisView> track;
1212 boost::shared_ptr<AutomationControl> control;
1215 switch (param.type()) {
1217 case GainAutomation:
1218 create_gain_automation_child (param, show);
1221 case MuteAutomation:
1222 create_mute_automation_child (param, show);
1225 case PluginAutomation:
1226 /* handled elsewhere */
1229 case MidiCCAutomation:
1230 case MidiPgmChangeAutomation:
1231 case MidiPitchBenderAutomation:
1232 case MidiChannelPressureAutomation:
1233 case MidiSystemExclusiveAutomation:
1234 /* These controllers are region "automation" - they are owned
1235 * by regions (and their MidiModels), not by the track. As a
1236 * result there is no AutomationList/Line for the track, but we create
1237 * a controller for the user to write immediate events, so the editor
1238 * can act as a control surface for the present MIDI controllers.
1240 * TODO: Record manipulation of the controller to regions?
1243 control = _route->automation_control(param, true);
1244 track.reset (new AutomationTimeAxisView (
1247 control ? _route : boost::shared_ptr<Automatable> (),
1254 _route->describe_parameter(param)));
1257 _view->foreach_regionview (
1258 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1261 add_automation_child (param, track, show);
1264 case PanWidthAutomation:
1265 case PanElevationAutomation:
1266 case PanAzimuthAutomation:
1267 ensure_pan_views (show);
1271 error << "MidiTimeAxisView: unknown automation child "
1272 << EventTypeMap::instance().to_symbol(param) << endmsg;
1277 MidiTimeAxisView::route_active_changed ()
1279 RouteUI::route_active_changed ();
1280 update_control_names();
1284 MidiTimeAxisView::update_control_names ()
1287 if (_route->active()) {
1288 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1289 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1291 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1292 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1294 } else { // MIDI bus (which doesn't exist yet..)
1295 if (_route->active()) {
1296 controls_base_selected_name = "BusControlsBaseSelected";
1297 controls_base_unselected_name = "BusControlsBaseUnselected";
1299 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1300 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1305 controls_ebox.set_name (controls_base_selected_name);
1306 time_axis_frame.set_name (controls_base_selected_name);
1308 controls_ebox.set_name (controls_base_unselected_name);
1309 time_axis_frame.set_name (controls_base_unselected_name);
1314 MidiTimeAxisView::set_note_selection (uint8_t note)
1316 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1318 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1320 if (_view->num_selected_regionviews() == 0) {
1321 _view->foreach_regionview (
1322 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1325 _view->foreach_selected_regionview (
1326 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1330 _editor.commit_reversible_selection_op();
1334 MidiTimeAxisView::add_note_selection (uint8_t note)
1336 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1338 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1340 if (_view->num_selected_regionviews() == 0) {
1341 _view->foreach_regionview (
1342 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1345 _view->foreach_selected_regionview (
1346 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1350 _editor.commit_reversible_selection_op();
1354 MidiTimeAxisView::extend_note_selection (uint8_t note)
1356 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1358 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1360 if (_view->num_selected_regionviews() == 0) {
1361 _view->foreach_regionview (
1362 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1365 _view->foreach_selected_regionview (
1366 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1370 _editor.commit_reversible_selection_op();
1374 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1376 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1378 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1380 if (_view->num_selected_regionviews() == 0) {
1381 _view->foreach_regionview (
1382 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1385 _view->foreach_selected_regionview (
1386 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1390 _editor.commit_reversible_selection_op();
1394 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1396 _view->foreach_regionview (
1397 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1401 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1403 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1407 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1409 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1413 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1415 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1419 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1421 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1425 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1427 Evoral::Sequence<Evoral::Beats>::Notes selected;
1428 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1430 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1432 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1433 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1434 notes.insert (*sel_it);
1437 if (!notes.empty()) {
1438 selection.push_back (make_pair ((rv)->region()->id(), notes));
1443 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1445 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1449 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1450 bool changed = false;
1454 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1456 for (uint32_t chn = 0; chn < 16; ++chn) {
1457 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1458 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1464 if ((selected_channels & (0x0001 << chn)) == 0) {
1465 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1466 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1468 changed = track->set_marked_for_display (false) || changed;
1470 changed = track->set_marked_for_display (true) || changed;
1477 /* TODO: Bender, Pressure */
1479 /* invalidate the controller menu, so that we rebuild it next time */
1480 _controller_menu_map.clear ();
1481 delete controller_menu;
1482 controller_menu = 0;
1490 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1492 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1497 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1498 if (i != _controller_menu_map.end()) {
1502 i = _channel_command_menu_map.find (param);
1503 if (i != _channel_command_menu_map.end()) {
1510 boost::shared_ptr<MidiRegion>
1511 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1513 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1515 real_editor->begin_reversible_command (Operations::create_region);
1517 playlist()->clear_changes ();
1519 real_editor->snap_to (pos, RoundNearest);
1521 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1524 plist.add (ARDOUR::Properties::start, 0);
1525 plist.add (ARDOUR::Properties::length, length);
1526 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1528 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1530 playlist()->add_region (region, pos);
1531 _session->add_command (new StatefulDiffCommand (playlist()));
1534 real_editor->commit_reversible_command ();
1537 return boost::dynamic_pointer_cast<MidiRegion>(region);
1541 MidiTimeAxisView::ensure_step_editor ()
1543 if (!_step_editor) {
1544 _step_editor = new StepEditor (_editor, midi_track(), *this);
1549 MidiTimeAxisView::start_step_editing ()
1551 ensure_step_editor ();
1552 _step_editor->start_step_editing ();
1556 MidiTimeAxisView::stop_step_editing ()
1559 _step_editor->stop_step_editing ();
1563 /** @return channel (counted from 0) to add an event to, based on the current setting
1564 * of the channel selector.
1567 MidiTimeAxisView::get_channel_for_add () const
1569 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1571 uint8_t channel = 0;
1573 /* pick the highest selected channel, unless all channels are selected,
1574 which is interpreted to mean channel 1 (zero)
1577 for (uint16_t i = 0; i < 16; ++i) {
1578 if (chn_mask & (1<<i)) {
1584 if (chn_cnt == 16) {
1592 MidiTimeAxisView::note_range_changed ()
1594 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1595 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1599 MidiTimeAxisView::contents_height_changed ()
1601 _range_scroomer->queue_resize ();
1605 MidiTimeAxisView::playback_channel_mode_changed ()
1607 switch (midi_track()->get_playback_channel_mode()) {
1609 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1611 case FilterChannels:
1612 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1615 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1621 MidiTimeAxisView::capture_channel_mode_changed ()
1623 switch (midi_track()->get_capture_channel_mode()) {
1625 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1627 case FilterChannels:
1628 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1631 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1637 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
1639 if (!_editor.internal_editing()) {
1640 // Non-internal paste, paste regions like any other route
1641 return RouteTimeAxisView::paste(pos, selection, ctx);
1644 return midi_view()->paste(pos, selection, ctx);