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)
122 , poly_pressure_menu (0)
125 _midnam_model_selector.disable_scrolling();
126 _midnam_custom_device_mode_selector.disable_scrolling();
130 MidiTimeAxisView::set_note_highlight (uint8_t note) {
131 _piano_roll_header->set_note_highlight (note);
135 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
139 _view = new MidiStreamView (*this);
142 _piano_roll_header = new PianoRollHeader(*midi_view());
143 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
144 _range_scroomer->DoubleClicked.connect (
145 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
146 MidiStreamView::ContentsRange, false));
149 /* This next call will result in our height being set up, so it must come after
150 the creation of the piano roll / range scroomer as their visibility is set up
153 RouteTimeAxisView::set_route (rt);
155 _view->apply_color (gdk_color_to_rgba (color()), StreamView::RegionColor);
157 subplugin_menu.set_name ("ArdourContextMenu");
159 if (!gui_property ("note-range-min").empty ()) {
160 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
161 atoi (gui_property ("note-range-max").c_str()),
165 midi_view()->NoteRangeChanged.connect (
166 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
167 _view->ContentsHeightChanged.connect (
168 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
170 ignore_toggle = false;
172 if (is_midi_track()) {
173 _note_mode = midi_track()->note_mode();
176 /* if set_state above didn't create a gain automation child, we need to make one */
177 if (automation_child (GainAutomation) == 0) {
178 create_automation_child (GainAutomation, false);
181 /* if set_state above didn't create a mute automation child, we need to make one */
182 if (automation_child (MuteAutomation) == 0) {
183 create_automation_child (MuteAutomation, false);
186 if (_route->panner_shell()) {
187 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
190 /* map current state of the route */
191 ensure_pan_views (false);
192 update_control_names();
193 processors_changed (RouteProcessorChange ());
195 _route->processors_changed.connect (*this, invalidator (*this),
196 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
200 _piano_roll_header->SetNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
202 _piano_roll_header->AddNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
204 _piano_roll_header->ExtendNoteSelection.connect (
205 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
206 _piano_roll_header->ToggleNoteSelection.connect (
207 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
209 /* Suspend updates of the StreamView during scroomer drags to speed things up */
210 _range_scroomer->DragStarting.connect (
211 sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
212 _range_scroomer->DragFinishing.connect (
213 sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
215 /* Put the scroomer and the keyboard in a VBox with a padding
216 label so that they can be reduced in height for stacked-view
220 HSeparator* separator = manage (new HSeparator());
221 separator->set_name("TrackSeparator");
222 separator->set_size_request(-1, 1);
225 VBox* v = manage (new VBox);
226 HBox* h = manage (new HBox);
227 h->pack_end (*_piano_roll_header);
228 h->pack_end (*_range_scroomer);
229 v->pack_start (*separator, false, false);
230 v->pack_start (*h, true, true);
233 top_hbox.remove(scroomer_placeholder);
234 time_axis_hbox.pack_end(*v, false, false, 0);
235 midi_scroomer_size_group->add_widget (*v);
237 midi_view()->NoteRangeChanged.connect (
238 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
240 /* ask for notifications of any new RegionViews */
241 _view->RegionViewAdded.connect (
242 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
244 midi_track()->playback_filter().ChannelModeChanged.connect (
245 *this, invalidator (*this),
246 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
248 midi_track()->playback_filter().ChannelMaskChanged.connect (
249 *this, invalidator (*this),
250 boost::bind (&MidiTimeAxisView::playback_channel_mode_changed, this),
252 midi_track()->capture_filter().ChannelModeChanged.connect (
253 *this, invalidator (*this),
254 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
256 midi_track()->capture_filter().ChannelMaskChanged.connect (
257 *this, invalidator (*this),
258 boost::bind (&MidiTimeAxisView::capture_channel_mode_changed, this),
261 playback_channel_mode_changed ();
262 capture_channel_mode_changed ();
264 if (!_editor.have_idled()) {
265 /* first idle will do what we need */
271 typedef MIDI::Name::MidiPatchManager PatchManager;
273 PatchManager& patch_manager = PatchManager::instance();
275 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
276 m != patch_manager.devices_by_manufacturer().end(); ++m) {
277 Menu* menu = Gtk::manage(new Menu);
278 Menu_Helpers::MenuList& items = menu->items();
280 // Build manufacturer submenu
281 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
282 n != m->second.end(); ++n) {
283 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
285 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
288 items.push_back(elem);
291 // Add manufacturer submenu to selector
292 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
295 if (gui_property (X_("midnam-model-name")).empty()) {
296 set_gui_property (X_("midnam-model-name"), "Generic");
299 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
300 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
302 set_gui_property (X_("midnam-custom-device-mode"),
303 *device_names->custom_device_mode_names().begin());
307 set_tooltip (_midnam_model_selector, _("External MIDI Device"));
308 set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
310 _midi_controls_box.set_homogeneous(false);
311 _midi_controls_box.set_border_width (2);
313 _channel_status_box.set_homogeneous (false);
314 _channel_status_box.set_spacing (4);
316 ArdourButton *channel_selector_button = manage (new ArdourButton(_("Chns")));
317 channel_selector_button->set_name ("route button");
318 set_tooltip (channel_selector_button, _("Click to edit channel settings"));
320 // Insert expanding space labels to get full width justification
321 _channel_status_box.pack_start (_playback_channel_status, false, false, 2);
322 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
323 _channel_status_box.pack_start (_capture_channel_status, false, false, 2);
324 _channel_status_box.pack_start (*Gtk::manage(new Gtk::Label(" ")), true, true);
325 _channel_status_box.pack_end (*channel_selector_button, false, false);
326 _channel_status_box.show_all ();
328 channel_selector_button->signal_clicked.connect (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_channel_selector));
330 _midi_controls_box.pack_start (_channel_status_box, false, false, 10);
332 if (!patch_manager.all_models().empty()) {
334 _midnam_model_selector.show ();
335 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
337 _midnam_custom_device_mode_selector.show ();
339 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
342 model_changed(gui_property(X_("midnam-model-name")));
343 custom_device_mode_changed(gui_property(X_("midnam-custom-device-mode")));
345 controls_vbox.pack_start(_midi_controls_box, false, false);
347 const string color_mode = gui_property ("color-mode");
348 if (!color_mode.empty()) {
349 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
350 if (_channel_selector && _color_mode == ChannelColors) {
351 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
355 set_color_mode (_color_mode, true, false);
357 const string note_mode = gui_property ("note-mode");
358 if (!note_mode.empty()) {
359 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
360 if (_percussion_mode_item) {
361 _percussion_mode_item->set_active (_note_mode == Percussive);
365 /* Look for any GUI object state nodes that represent automation children
366 * that should exist, and create the children.
369 const list<string> gui_ids = gui_object_state().all_ids ();
370 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
373 Evoral::Parameter parameter (0, 0, 0);
375 bool const p = AutomationTimeAxisView::parse_state_id (
376 *i, route_id, has_parameter, parameter);
377 if (p && route_id == _route->id () && has_parameter) {
378 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
379 create_automation_child (parameter, string_is_affirmative (visible));
385 MidiTimeAxisView::first_idle ()
392 MidiTimeAxisView::~MidiTimeAxisView ()
394 delete _channel_selector;
396 delete _piano_roll_header;
397 _piano_roll_header = 0;
399 delete _range_scroomer;
402 delete controller_menu;
407 MidiTimeAxisView::check_step_edit ()
409 ensure_step_editor ();
410 _step_editor->check_step_edit ();
414 MidiTimeAxisView::model_changed(const std::string& model)
416 set_gui_property (X_("midnam-model-name"), model);
418 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
419 .custom_device_mode_names_by_model(model);
421 _midnam_model_selector.set_text(model);
422 _midnam_custom_device_mode_selector.clear_items();
424 for (std::list<std::string>::const_iterator i = device_modes.begin();
425 i != device_modes.end(); ++i) {
426 _midnam_custom_device_mode_selector.AddMenuElem(
427 Gtk::Menu_Helpers::MenuElem(
428 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
432 if (!device_modes.empty()) {
433 custom_device_mode_changed(device_modes.front());
436 if (device_modes.size() > 1) {
437 _midnam_custom_device_mode_selector.show();
439 _midnam_custom_device_mode_selector.hide();
442 if (device_modes.size() > 0) {
443 _route->instrument_info().set_external_instrument (model, device_modes.front());
445 _route->instrument_info().set_external_instrument (model, "");
448 // Rebuild controller menu
449 _controller_menu_map.clear ();
450 delete controller_menu;
452 build_automation_action_menu(false);
456 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
458 const std::string model = gui_property (X_("midnam-model-name"));
460 set_gui_property (X_("midnam-custom-device-mode"), mode);
461 _midnam_custom_device_mode_selector.set_text(mode);
462 _route->instrument_info().set_external_instrument (model, mode);
466 MidiTimeAxisView::midi_view()
468 return dynamic_cast<MidiStreamView*>(_view);
472 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
474 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
475 _midi_controls_box.show ();
477 _midi_controls_box.hide();
480 if (h >= KEYBOARD_MIN_HEIGHT) {
481 if (is_track() && _range_scroomer) {
482 _range_scroomer->show();
484 if (is_track() && _piano_roll_header) {
485 _piano_roll_header->show();
488 if (is_track() && _range_scroomer) {
489 _range_scroomer->hide();
491 if (is_track() && _piano_roll_header) {
492 _piano_roll_header->hide();
496 /* We need to do this after changing visibility of our stuff, as it will
497 eventually trigger a call to Editor::reset_controls_layout_width(),
498 which needs to know if we have just shown or hidden a scroomer /
501 RouteTimeAxisView::set_height (h, m);
505 MidiTimeAxisView::append_extra_display_menu_items ()
507 using namespace Menu_Helpers;
509 MenuList& items = display_menu->items();
512 Menu *range_menu = manage(new Menu);
513 MenuList& range_items = range_menu->items();
514 range_menu->set_name ("ArdourContextMenu");
516 range_items.push_back (
517 MenuElem (_("Show Full Range"),
518 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
519 MidiStreamView::FullRange, true)));
521 range_items.push_back (
522 MenuElem (_("Fit Contents"),
523 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
524 MidiStreamView::ContentsRange, true)));
526 items.push_back (MenuElem (_("Note Range"), *range_menu));
527 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
528 items.push_back (MenuElem (_("Channel Selector"),
529 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
531 color_mode_menu = build_color_mode_menu();
532 if (color_mode_menu) {
533 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
536 items.push_back (SeparatorElem ());
540 MidiTimeAxisView::toggle_channel_selector ()
542 if (!_channel_selector) {
543 _channel_selector = new MidiChannelSelectorWindow (midi_track());
545 if (_color_mode == ChannelColors) {
546 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
548 _channel_selector->set_default_channel_color ();
551 _channel_selector->show_all ();
553 _channel_selector->cycle_visibility ();
558 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
560 using namespace Menu_Helpers;
562 /* If we have a controller menu, we need to detach it before
563 RouteTimeAxis::build_automation_action_menu destroys the
564 menu it is attached to. Otherwise GTK destroys
565 controller_menu's gobj, meaning that it can't be reattached
566 below. See bug #3134.
569 if (controller_menu) {
570 detach_menu (*controller_menu);
573 _channel_command_menu_map.clear ();
574 RouteTimeAxisView::build_automation_action_menu (for_selection);
576 MenuList& automation_items = automation_action_menu->items();
578 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
580 if (selected_channels != 0) {
582 automation_items.push_back (SeparatorElem());
584 /* these 2 MIDI "command" types are semantically more like automation
585 than note data, but they are not MIDI controllers. We give them
586 special status in this menu, since they will not show up in the
587 controller list and anyone who actually knows something about MIDI
588 (!) would not expect to find them there.
591 add_channel_command_menu_item (
592 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
593 automation_items.back().set_sensitive (
594 !for_selection || _editor.get_selection().tracks.size() == 1);
595 add_channel_command_menu_item (
596 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
597 automation_items.back().set_sensitive (
598 !for_selection || _editor.get_selection().tracks.size() == 1);
600 /* now all MIDI controllers. Always offer the possibility that we will
601 rebuild the controllers menu since it might need to be updated after
602 a channel mode change or other change. Also detach it first in case
603 it has been used anywhere else.
606 build_controller_menu ();
608 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
610 if (!poly_pressure_menu) {
611 poly_pressure_menu = new Gtk::Menu;
614 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
616 automation_items.back().set_sensitive (
617 !for_selection || _editor.get_selection().tracks.size() == 1);
619 automation_items.push_back (
620 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
621 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
626 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
628 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
630 for (uint8_t chn = 0; chn < 16; chn++) {
631 if (selected_channels & (0x0001 << chn)) {
633 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
634 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
637 menu->set_active (yn);
644 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
646 AutomationType auto_type,
649 using namespace Menu_Helpers;
651 /* count the number of selected channels because we will build a different menu
652 structure if there is more than 1 selected.
655 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
658 for (uint8_t chn = 0; chn < 16; chn++) {
659 if (selected_channels & (0x0001 << chn)) {
668 /* multiple channels - create a submenu, with 1 item per channel */
670 Menu* chn_menu = manage (new Menu);
671 MenuList& chn_items (chn_menu->items());
672 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
674 /* add a couple of items to hide/show all of them */
676 chn_items.push_back (
677 MenuElem (_("Hide all channels"),
678 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
679 false, param_without_channel)));
680 chn_items.push_back (
681 MenuElem (_("Show all channels"),
682 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
683 true, param_without_channel)));
685 for (uint8_t chn = 0; chn < 16; chn++) {
686 if (selected_channels & (0x0001 << chn)) {
688 /* for each selected channel, add a menu item for this controller */
690 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
691 chn_items.push_back (
692 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
693 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
694 fully_qualified_param)));
696 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
697 bool visible = false;
700 if (track->marked_for_display()) {
705 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
706 _channel_command_menu_map[fully_qualified_param] = cmi;
707 cmi->set_active (visible);
711 /* now create an item in the parent menu that has the per-channel list as a submenu */
713 items.push_back (MenuElem (label, *chn_menu));
717 /* just one channel - create a single menu item for this command+channel combination*/
719 for (uint8_t chn = 0; chn < 16; chn++) {
720 if (selected_channels & (0x0001 << chn)) {
722 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
724 CheckMenuElem (label,
725 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
726 fully_qualified_param)));
728 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
729 bool visible = false;
732 if (track->marked_for_display()) {
737 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
738 _channel_command_menu_map[fully_qualified_param] = cmi;
739 cmi->set_active (visible);
741 /* one channel only */
748 /** Add a single menu item for a controller on one channel. */
750 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
752 const std::string& name)
754 using namespace Menu_Helpers;
756 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
757 for (uint8_t chn = 0; chn < 16; chn++) {
758 if (selected_channels & (0x0001 << chn)) {
760 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
761 ctl_items.push_back (
763 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
765 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
766 fully_qualified_param)));
767 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
769 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
770 fully_qualified_param);
772 bool visible = false;
774 if (track->marked_for_display()) {
779 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
780 _controller_menu_map[fully_qualified_param] = cmi;
781 cmi->set_active (visible);
783 /* one channel only */
789 /** Add a submenu with 1 item per channel for a controller on many channels. */
791 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
793 const std::string& name)
795 using namespace Menu_Helpers;
797 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
799 Menu* chn_menu = manage (new Menu);
800 MenuList& chn_items (chn_menu->items());
802 /* add a couple of items to hide/show this controller on all channels */
804 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
805 chn_items.push_back (
806 MenuElem (_("Hide all channels"),
807 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
808 false, param_without_channel)));
809 chn_items.push_back (
810 MenuElem (_("Show all channels"),
811 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
812 true, param_without_channel)));
814 for (uint8_t chn = 0; chn < 16; chn++) {
815 if (selected_channels & (0x0001 << chn)) {
817 /* for each selected channel, add a menu item for this controller */
819 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
820 chn_items.push_back (
821 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
822 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
823 fully_qualified_param)));
825 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
826 fully_qualified_param);
827 bool visible = false;
830 if (track->marked_for_display()) {
835 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
836 _controller_menu_map[fully_qualified_param] = cmi;
837 cmi->set_active (visible);
841 /* add the per-channel menu to the list of controllers, with the name of the controller */
842 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
844 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
847 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
848 MidiTimeAxisView::get_device_mode()
850 using namespace MIDI::Name;
852 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
854 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
857 return device_names->custom_device_mode_by_name(
858 gui_property (X_("midnam-custom-device-mode")));
861 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
862 MidiTimeAxisView::get_device_names()
864 using namespace MIDI::Name;
866 const std::string model = gui_property (X_("midnam-model-name"));
868 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
869 .document_by_model(model);
871 return midnam->master_device_names(model);
873 return boost::shared_ptr<MasterDeviceNames>();
878 MidiTimeAxisView::build_controller_menu ()
880 using namespace Menu_Helpers;
882 if (controller_menu) {
883 /* it exists and has not been invalidated by a channel mode change */
887 controller_menu = new Menu; // explicitly managed by us
888 MenuList& items (controller_menu->items());
890 /* create several "top level" menu items for sets of controllers (16 at a
891 time), and populate each one with a submenu for each controller+channel
892 combination covering the currently selected channels for this track
895 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
897 /* count the number of selected channels because we will build a different menu
898 structure if there is more than 1 selected.
902 for (uint8_t chn = 0; chn < 16; chn++) {
903 if (selected_channels & (0x0001 << chn)) {
910 using namespace MIDI::Name;
911 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
913 if (device_names && !device_names->controls().empty()) {
914 /* Controllers names available in midnam file, generate fancy menu */
915 unsigned n_items = 0;
916 unsigned n_groups = 0;
918 /* TODO: This is not correct, should look up the currently applicable ControlNameList
919 and only build a menu for that one. */
920 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
921 l != device_names->controls().end(); ++l) {
922 boost::shared_ptr<ControlNameList> name_list = l->second;
923 Menu* ctl_menu = NULL;
925 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
926 c != name_list->controls().end();) {
927 const uint16_t ctl = c->second->number();
928 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
929 /* Skip bank select controllers since they're handled specially */
931 /* Create a new submenu */
932 ctl_menu = manage (new Menu);
935 MenuList& ctl_items (ctl_menu->items());
937 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
939 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
944 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
945 /* Submenu has 16 items or we're done, add it to controller menu and reset */
947 MenuElem(string_compose(_("Controllers %1-%2"),
948 (16 * n_groups), (16 * n_groups) + n_items - 1),
957 /* No controllers names, generate generic numeric menu */
958 for (int i = 0; i < 127; i += 16) {
959 Menu* ctl_menu = manage (new Menu);
960 MenuList& ctl_items (ctl_menu->items());
962 for (int ctl = i; ctl < i+16; ++ctl) {
963 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
964 /* Skip bank select controllers since they're handled specially */
969 add_multi_channel_controller_item(
970 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
972 add_single_channel_controller_item(
973 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
977 /* Add submenu for this block of controllers to controller menu */
979 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
986 MidiTimeAxisView::build_note_mode_menu()
988 using namespace Menu_Helpers;
990 Menu* mode_menu = manage (new Menu);
991 MenuList& items = mode_menu->items();
992 mode_menu->set_name ("ArdourContextMenu");
994 RadioMenuItem::Group mode_group;
996 RadioMenuElem (mode_group,_("Sustained"),
997 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
999 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1000 _note_mode_item->set_active(_note_mode == Sustained);
1003 RadioMenuElem (mode_group, _("Percussive"),
1004 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1005 Percussive, true)));
1006 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1007 _percussion_mode_item->set_active(_note_mode == Percussive);
1013 MidiTimeAxisView::build_color_mode_menu()
1015 using namespace Menu_Helpers;
1017 Menu* mode_menu = manage (new Menu);
1018 MenuList& items = mode_menu->items();
1019 mode_menu->set_name ("ArdourContextMenu");
1021 RadioMenuItem::Group mode_group;
1023 RadioMenuElem (mode_group, _("Meter Colors"),
1024 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1025 MeterColors, false, true, true)));
1026 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1027 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1030 RadioMenuElem (mode_group, _("Channel Colors"),
1031 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1032 ChannelColors, false, true, true)));
1033 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1034 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1037 RadioMenuElem (mode_group, _("Track Color"),
1038 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1039 TrackColor, false, true, true)));
1040 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1041 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1047 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1049 if (apply_to_selection) {
1050 _editor.get_selection().tracks.foreach_midi_time_axis (
1051 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1053 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1055 midi_track()->set_note_mode(mode);
1056 set_gui_property ("note-mode", enum_2_string(_note_mode));
1057 _view->redisplay_track();
1063 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1065 if (apply_to_selection) {
1066 _editor.get_selection().tracks.foreach_midi_time_axis (
1067 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1069 if (_color_mode == mode && !force) {
1073 if (_channel_selector) {
1074 if (mode == ChannelColors) {
1075 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1077 _channel_selector->set_default_channel_color();
1082 set_gui_property ("color-mode", enum_2_string(_color_mode));
1084 _view->redisplay_track();
1090 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1092 if (apply_to_selection) {
1093 _editor.get_selection().tracks.foreach_midi_time_axis (
1094 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1096 if (!_ignore_signals) {
1097 midi_view()->set_note_range(range);
1103 MidiTimeAxisView::update_range()
1105 MidiGhostRegion* mgr;
1107 for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1108 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1109 mgr->update_range();
1115 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1117 using namespace MIDI::Name;
1119 if (apply_to_selection) {
1120 _editor.get_selection().tracks.foreach_midi_time_axis (
1121 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1124 // Show existing automation
1125 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1127 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1128 create_automation_child(*i, true);
1131 // Show automation for all controllers named in midnam file
1132 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1133 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1134 device_names && !device_names->controls().empty()) {
1135 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1136 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1137 for (uint32_t chn = 0; chn < 16; ++chn) {
1138 if ((selected_channels & (0x0001 << chn)) == 0) {
1139 // Channel not in use
1143 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1149 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1150 chan_names->control_list_name());
1151 if (!control_names) {
1155 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1156 c != control_names->controls().end();
1158 const uint16_t ctl = c->second->number();
1159 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1160 /* Skip bank select controllers since they're handled specially */
1161 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1162 create_automation_child(param, true);
1169 RouteTimeAxisView::show_all_automation ();
1174 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1176 if (apply_to_selection) {
1177 _editor.get_selection().tracks.foreach_midi_time_axis (
1178 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1181 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1183 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1184 create_automation_child (*i, true);
1188 RouteTimeAxisView::show_existing_automation ();
1192 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1195 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1197 if (param.type() == NullAutomation) {
1201 AutomationTracks::iterator existing = _automation_tracks.find (param);
1203 if (existing != _automation_tracks.end()) {
1205 /* automation track created because we had existing data for
1206 * the processor, but visibility may need to be controlled
1207 * since it will have been set visible by default.
1210 existing->second->set_marked_for_display (show);
1219 boost::shared_ptr<AutomationTimeAxisView> track;
1220 boost::shared_ptr<AutomationControl> control;
1223 switch (param.type()) {
1225 case GainAutomation:
1226 create_gain_automation_child (param, show);
1229 case MuteAutomation:
1230 create_mute_automation_child (param, show);
1233 case PluginAutomation:
1234 /* handled elsewhere */
1237 case MidiCCAutomation:
1238 case MidiPgmChangeAutomation:
1239 case MidiPitchBenderAutomation:
1240 case MidiChannelPressureAutomation:
1241 case MidiSystemExclusiveAutomation:
1242 /* These controllers are region "automation" - they are owned
1243 * by regions (and their MidiModels), not by the track. As a
1244 * result there is no AutomationList/Line for the track, but we create
1245 * a controller for the user to write immediate events, so the editor
1246 * can act as a control surface for the present MIDI controllers.
1248 * TODO: Record manipulation of the controller to regions?
1251 control = _route->automation_control(param, true);
1252 track.reset (new AutomationTimeAxisView (
1255 control ? _route : boost::shared_ptr<Automatable> (),
1262 _route->describe_parameter(param)));
1265 _view->foreach_regionview (
1266 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1269 add_automation_child (param, track, show);
1272 case PanWidthAutomation:
1273 case PanElevationAutomation:
1274 case PanAzimuthAutomation:
1275 ensure_pan_views (show);
1279 error << "MidiTimeAxisView: unknown automation child "
1280 << EventTypeMap::instance().to_symbol(param) << endmsg;
1285 MidiTimeAxisView::route_active_changed ()
1287 RouteUI::route_active_changed ();
1288 update_control_names();
1292 MidiTimeAxisView::update_control_names ()
1295 if (_route->active()) {
1296 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1297 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1299 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1300 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1302 } else { // MIDI bus (which doesn't exist yet..)
1303 if (_route->active()) {
1304 controls_base_selected_name = "BusControlsBaseSelected";
1305 controls_base_unselected_name = "BusControlsBaseUnselected";
1307 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1308 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1313 controls_ebox.set_name (controls_base_selected_name);
1314 time_axis_frame.set_name (controls_base_selected_name);
1316 controls_ebox.set_name (controls_base_unselected_name);
1317 time_axis_frame.set_name (controls_base_unselected_name);
1322 MidiTimeAxisView::set_note_selection (uint8_t note)
1324 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1326 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1328 if (_view->num_selected_regionviews() == 0) {
1329 _view->foreach_regionview (
1330 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1333 _view->foreach_selected_regionview (
1334 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1338 _editor.commit_reversible_selection_op();
1342 MidiTimeAxisView::add_note_selection (uint8_t note)
1344 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1346 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1348 if (_view->num_selected_regionviews() == 0) {
1349 _view->foreach_regionview (
1350 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1353 _view->foreach_selected_regionview (
1354 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1358 _editor.commit_reversible_selection_op();
1362 MidiTimeAxisView::extend_note_selection (uint8_t note)
1364 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1366 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1368 if (_view->num_selected_regionviews() == 0) {
1369 _view->foreach_regionview (
1370 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1373 _view->foreach_selected_regionview (
1374 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1378 _editor.commit_reversible_selection_op();
1382 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1384 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1386 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1388 if (_view->num_selected_regionviews() == 0) {
1389 _view->foreach_regionview (
1390 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1393 _view->foreach_selected_regionview (
1394 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1398 _editor.commit_reversible_selection_op();
1402 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1404 _view->foreach_regionview (
1405 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1409 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1411 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1415 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1417 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1421 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1423 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1427 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1429 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1433 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1435 Evoral::Sequence<Evoral::Beats>::Notes selected;
1436 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1438 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1440 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1441 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1442 notes.insert (*sel_it);
1445 if (!notes.empty()) {
1446 selection.push_back (make_pair ((rv)->region()->id(), notes));
1451 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1453 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1457 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1458 bool changed = false;
1462 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1464 for (uint32_t chn = 0; chn < 16; ++chn) {
1465 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1466 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1472 if ((selected_channels & (0x0001 << chn)) == 0) {
1473 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1474 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1476 changed = track->set_marked_for_display (false) || changed;
1478 changed = track->set_marked_for_display (true) || changed;
1485 /* TODO: Bender, Pressure */
1487 /* invalidate the controller menu, so that we rebuild it next time */
1488 _controller_menu_map.clear ();
1489 delete controller_menu;
1490 controller_menu = 0;
1498 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1500 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1505 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1506 if (i != _controller_menu_map.end()) {
1510 i = _channel_command_menu_map.find (param);
1511 if (i != _channel_command_menu_map.end()) {
1518 boost::shared_ptr<MidiRegion>
1519 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit, const int32_t sub_num)
1521 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1523 real_editor->begin_reversible_command (Operations::create_region);
1525 playlist()->clear_changes ();
1527 real_editor->snap_to (pos, RoundNearest);
1529 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1532 plist.add (ARDOUR::Properties::start, 0);
1533 plist.add (ARDOUR::Properties::length, length);
1534 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1536 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1537 /* sets beat position */
1538 region->set_position (pos, sub_num);
1539 playlist()->add_region (region, pos, 1.0, false, sub_num);
1540 _session->add_command (new StatefulDiffCommand (playlist()));
1543 real_editor->commit_reversible_command ();
1546 return boost::dynamic_pointer_cast<MidiRegion>(region);
1550 MidiTimeAxisView::ensure_step_editor ()
1552 if (!_step_editor) {
1553 _step_editor = new StepEditor (_editor, midi_track(), *this);
1558 MidiTimeAxisView::start_step_editing ()
1560 ensure_step_editor ();
1561 _step_editor->start_step_editing ();
1565 MidiTimeAxisView::stop_step_editing ()
1568 _step_editor->stop_step_editing ();
1572 /** @return channel (counted from 0) to add an event to, based on the current setting
1573 * of the channel selector.
1576 MidiTimeAxisView::get_channel_for_add () const
1578 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1580 uint8_t channel = 0;
1582 /* pick the highest selected channel, unless all channels are selected,
1583 which is interpreted to mean channel 1 (zero)
1586 for (uint16_t i = 0; i < 16; ++i) {
1587 if (chn_mask & (1<<i)) {
1593 if (chn_cnt == 16) {
1601 MidiTimeAxisView::note_range_changed ()
1603 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1604 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1608 MidiTimeAxisView::contents_height_changed ()
1610 _range_scroomer->queue_resize ();
1614 MidiTimeAxisView::playback_channel_mode_changed ()
1616 switch (midi_track()->get_playback_channel_mode()) {
1618 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("all")));
1620 case FilterChannels:
1621 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Play"), _("some")));
1624 _playback_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Play"), _("all"), PBD::ffs (midi_track()->get_playback_channel_mask())));
1630 MidiTimeAxisView::capture_channel_mode_changed ()
1632 switch (midi_track()->get_capture_channel_mode()) {
1634 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("all")));
1636 case FilterChannels:
1637 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2</i>", _("Rec"), _("some")));
1640 _capture_channel_status.set_markup (string_compose ("<b>%1</b>: <i>%2>%3</i>", _("Rec"), _("all"), PBD::ffs (midi_track()->get_capture_channel_mask())));
1646 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1648 if (!_editor.internal_editing()) {
1649 // Non-internal paste, paste regions like any other route
1650 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1653 return midi_view()->paste(pos, selection, ctx, sub_num);