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 <gtkmm/separator.h>
29 #include <gtkmm/stock.h>
31 #include "pbd/error.h"
33 #include "pbd/stl_delete.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/basename.h"
36 #include "pbd/enumwriter.h"
37 #include "pbd/memento_command.h"
38 #include "pbd/stateful_diff_command.h"
40 #include "gtkmm2ext/gtk_ui.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/tooltips.h"
45 #include "ardour/event_type_map.h"
46 #include "ardour/midi_patch_manager.h"
47 #include "ardour/midi_playlist.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_source.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/operations.h"
52 #include "ardour/pannable.h"
53 #include "ardour/panner.h"
54 #include "ardour/panner_shell.h"
55 #include "ardour/playlist.h"
56 #include "ardour/plugin_insert.h"
57 #include "ardour/profile.h"
58 #include "ardour/region.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/route.h"
61 #include "ardour/session.h"
62 #include "ardour/session_object.h"
63 #include "ardour/source.h"
64 #include "ardour/track.h"
65 #include "ardour/types.h"
67 #include "automation_line.h"
68 #include "automation_time_axis.h"
71 #include "ghostregion.h"
72 #include "gui_thread.h"
74 #include "midi_channel_selector.h"
75 #include "midi_scroomer.h"
76 #include "midi_streamview.h"
77 #include "midi_region_view.h"
78 #include "midi_time_axis.h"
79 #include "patch_change_dialog.h"
80 #include "patch_change_widget.h"
81 #include "piano_roll_header.h"
82 #include "playlist_selector.h"
83 #include "plugin_selector.h"
84 #include "plugin_ui.h"
85 #include "point_selection.h"
86 #include "region_view.h"
87 #include "rgb_macros.h"
88 #include "selection.h"
89 #include "step_editor.h"
91 #include "note_base.h"
93 #include "ardour/midi_track.h"
97 using namespace ARDOUR;
100 using namespace Gtkmm2ext;
101 using namespace Editing;
104 // Minimum height at which a control is displayed
105 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
106 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
108 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
109 : SessionHandlePtr (sess)
110 , RouteTimeAxisView (ed, sess, canvas)
111 , _ignore_signals(false)
113 , _piano_roll_header(0)
114 , _note_mode(Sustained)
116 , _percussion_mode_item(0)
117 , _color_mode(MeterColors)
118 , _meter_color_mode_item(0)
119 , _channel_color_mode_item(0)
120 , _track_color_mode_item(0)
121 , _channel_selector (0)
122 , _step_edit_item (0)
123 , controller_menu (0)
124 , poly_pressure_menu (0)
127 _midnam_model_selector.disable_scrolling();
128 _midnam_custom_device_mode_selector.disable_scrolling();
132 MidiTimeAxisView::set_note_highlight (uint8_t note) {
133 _piano_roll_header->set_note_highlight (note);
137 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
141 _view = new MidiStreamView (*this);
144 _piano_roll_header = new PianoRollHeader(*midi_view());
145 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
146 _range_scroomer->DoubleClicked.connect (
147 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
148 MidiStreamView::ContentsRange, false));
151 /* This next call will result in our height being set up, so it must come after
152 the creation of the piano roll / range scroomer as their visibility is set up
155 RouteTimeAxisView::set_route (rt);
157 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
159 subplugin_menu.set_name ("ArdourContextMenu");
161 _note_range_changed_connection.disconnect();
163 if (!gui_property ("note-range-min").empty ()) {
164 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
165 atoi (gui_property ("note-range-max").c_str()),
169 _view->ContentsHeightChanged.connect (
170 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
172 ignore_toggle = false;
174 if (is_midi_track()) {
175 _note_mode = midi_track()->note_mode();
178 /* if set_state above didn't create a gain automation child, we need to make one */
179 if (automation_child (GainAutomation) == 0) {
180 create_automation_child (GainAutomation, false);
183 /* if set_state above didn't create a mute automation child, we need to make one */
184 if (automation_child (MuteAutomation) == 0) {
185 create_automation_child (MuteAutomation, false);
188 if (_route->panner_shell()) {
189 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
192 /* map current state of the route */
193 ensure_pan_views (false);
194 update_control_names();
195 processors_changed (RouteProcessorChange ());
198 _piano_roll_header->SetNoteSelection.connect (
199 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
200 _piano_roll_header->AddNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
202 _piano_roll_header->ExtendNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
204 _piano_roll_header->ToggleNoteSelection.connect (
205 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
207 /* Put the scroomer and the keyboard in a VBox with a padding
208 label so that they can be reduced in height for stacked-view
212 HSeparator* separator = manage (new HSeparator());
213 separator->set_name("TrackSeparator");
214 separator->set_size_request(-1, 1);
217 VBox* v = manage (new VBox);
218 HBox* h = manage (new HBox);
219 h->pack_end (*_piano_roll_header);
220 h->pack_end (*_range_scroomer);
221 v->pack_start (*separator, false, false);
222 v->pack_start (*h, true, true);
225 top_hbox.remove(scroomer_placeholder);
226 time_axis_hbox.pack_end(*v, false, false, 0);
227 midi_scroomer_size_group->add_widget (*v);
229 /* callback from StreamView scroomer drags, as well as
230 * automatic changes of note-range (e.g. at rec-stop).
231 * This callback is used to save the note-range-min/max
232 * GUI Object property
234 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
235 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
237 /* ask for notifications of any new RegionViews */
238 _view->RegionViewAdded.connect (
239 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
241 if (!_editor.have_idled()) {
242 /* first idle will do what we need */
248 if (gui_property (X_("midnam-model-name")).empty()) {
249 set_gui_property (X_("midnam-model-name"), "Generic");
252 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
253 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
255 set_gui_property (X_("midnam-custom-device-mode"),
256 *device_names->custom_device_mode_names().begin());
260 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
261 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
263 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
264 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
266 _midi_controls_box.set_homogeneous(false);
267 _midi_controls_box.set_border_width (2);
269 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
270 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
273 setup_midnam_patches ();
274 update_patch_selector ();
276 model_changed (gui_property(X_("midnam-model-name")));
277 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
279 controls_vbox.pack_start(_midi_controls_box, false, false);
281 const string color_mode = gui_property ("color-mode");
282 if (!color_mode.empty()) {
283 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
284 if (_channel_selector && _color_mode == ChannelColors) {
285 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
289 set_color_mode (_color_mode, true, false);
291 const string note_mode = gui_property ("note-mode");
292 if (!note_mode.empty()) {
293 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
294 if (_percussion_mode_item) {
295 _percussion_mode_item->set_active (_note_mode == Percussive);
299 /* Look for any GUI object state nodes that represent automation children
300 * that should exist, and create the children.
303 const list<string> gui_ids = gui_object_state().all_ids ();
304 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
307 Evoral::Parameter parameter (0, 0, 0);
309 bool const p = AutomationTimeAxisView::parse_state_id (
310 *i, route_id, has_parameter, parameter);
311 if (p && route_id == _route->id () && has_parameter) {
312 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
313 create_automation_child (parameter, string_to<bool> (visible));
319 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
321 RouteTimeAxisView::processors_changed (c);
322 update_patch_selector ();
326 MidiTimeAxisView::first_idle ()
333 MidiTimeAxisView::~MidiTimeAxisView ()
335 delete _channel_selector;
337 delete _piano_roll_header;
338 _piano_roll_header = 0;
340 delete _range_scroomer;
343 delete controller_menu;
348 MidiTimeAxisView::check_step_edit ()
350 ensure_step_editor ();
351 _step_editor->check_step_edit ();
355 MidiTimeAxisView::setup_midnam_patches ()
357 typedef MIDI::Name::MidiPatchManager PatchManager;
358 PatchManager& patch_manager = PatchManager::instance();
360 _midnam_model_selector.clear_items ();
361 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
362 m != patch_manager.devices_by_manufacturer().end(); ++m) {
363 Menu* menu = Gtk::manage(new Menu);
364 Menu_Helpers::MenuList& items = menu->items();
366 // Build manufacturer submenu
367 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
368 n != m->second.end(); ++n) {
369 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
371 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
374 items.push_back(elem);
377 // Add manufacturer submenu to selector
378 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
381 if (!get_device_names()) {
382 model_changed ("Generic");
387 MidiTimeAxisView::update_patch_selector ()
389 typedef MIDI::Name::MidiPatchManager PatchManager;
390 PatchManager& patch_manager = PatchManager::instance();
392 bool pluginprovided = false;
394 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
395 if (pi && pi->plugin ()->has_midnam ()) {
396 pluginprovided = true;
397 std::string model_name = pi->plugin ()->midnam_model ();
398 if (gui_property (X_("midnam-model-name")) != model_name) {
399 model_changed (model_name);
404 if (patch_manager.all_models().empty() || pluginprovided) {
405 _midnam_model_selector.hide ();
406 _midnam_custom_device_mode_selector.hide ();
408 _midnam_model_selector.show ();
409 _midnam_custom_device_mode_selector.show ();
415 MidiTimeAxisView::model_changed(const std::string& model)
417 set_gui_property (X_("midnam-model-name"), model);
419 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
420 .custom_device_mode_names_by_model(model);
422 _midnam_model_selector.set_text(model);
423 _midnam_custom_device_mode_selector.clear_items();
425 for (std::list<std::string>::const_iterator i = device_modes.begin();
426 i != device_modes.end(); ++i) {
427 _midnam_custom_device_mode_selector.AddMenuElem(
428 Gtk::Menu_Helpers::MenuElem(
429 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
433 if (!device_modes.empty()) {
434 custom_device_mode_changed(device_modes.front());
437 if (device_modes.size() > 1) {
438 _midnam_custom_device_mode_selector.show();
440 _midnam_custom_device_mode_selector.hide();
443 // now this is a real bad hack
444 if (device_modes.size() > 0) {
445 _route->instrument_info().set_external_instrument (model, device_modes.front());
447 _route->instrument_info().set_external_instrument (model, "");
450 // Rebuild controller menu
451 _controller_menu_map.clear ();
452 delete controller_menu;
454 build_automation_action_menu(false);
456 if (patch_change_dialog ()) {
457 patch_change_dialog ()->refresh ();
462 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
464 const std::string model = gui_property (X_("midnam-model-name"));
466 set_gui_property (X_("midnam-custom-device-mode"), mode);
467 _midnam_custom_device_mode_selector.set_text(mode);
468 _route->instrument_info().set_external_instrument (model, mode);
472 MidiTimeAxisView::midi_view()
474 return dynamic_cast<MidiStreamView*>(_view);
478 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
480 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
481 _midi_controls_box.show ();
483 _midi_controls_box.hide();
486 if (h >= KEYBOARD_MIN_HEIGHT) {
487 if (is_track() && _range_scroomer) {
488 _range_scroomer->show();
490 if (is_track() && _piano_roll_header) {
491 _piano_roll_header->show();
494 if (is_track() && _range_scroomer) {
495 _range_scroomer->hide();
497 if (is_track() && _piano_roll_header) {
498 _piano_roll_header->hide();
502 /* We need to do this after changing visibility of our stuff, as it will
503 eventually trigger a call to Editor::reset_controls_layout_width(),
504 which needs to know if we have just shown or hidden a scroomer /
507 RouteTimeAxisView::set_height (h, m);
511 MidiTimeAxisView::append_extra_display_menu_items ()
513 using namespace Menu_Helpers;
515 MenuList& items = display_menu->items();
518 Menu *range_menu = manage(new Menu);
519 MenuList& range_items = range_menu->items();
520 range_menu->set_name ("ArdourContextMenu");
522 range_items.push_back (
523 MenuElem (_("Show Full Range"),
524 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
525 MidiStreamView::FullRange, true)));
527 range_items.push_back (
528 MenuElem (_("Fit Contents"),
529 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
530 MidiStreamView::ContentsRange, true)));
532 items.push_back (MenuElem (_("Note Range"), *range_menu));
533 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
534 items.push_back (MenuElem (_("Channel Selector..."),
535 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
537 items.push_back (MenuElem (_("Patch Selector..."),
538 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
540 items.push_back (MenuElem (_("Color Mode"), *build_color_mode_menu ()));
542 items.push_back (SeparatorElem ());
546 MidiTimeAxisView::toggle_channel_selector ()
548 if (!_channel_selector) {
549 _channel_selector = new MidiChannelSelectorWindow (midi_track());
551 if (_color_mode == ChannelColors) {
552 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
554 _channel_selector->set_default_channel_color ();
557 _channel_selector->show_all ();
559 _channel_selector->cycle_visibility ();
564 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
566 using namespace Menu_Helpers;
568 /* If we have a controller menu, we need to detach it before
569 RouteTimeAxis::build_automation_action_menu destroys the
570 menu it is attached to. Otherwise GTK destroys
571 controller_menu's gobj, meaning that it can't be reattached
572 below. See bug #3134.
575 if (controller_menu) {
576 detach_menu (*controller_menu);
579 _channel_command_menu_map.clear ();
580 RouteTimeAxisView::build_automation_action_menu (for_selection);
582 MenuList& automation_items = automation_action_menu->items();
584 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
586 if (selected_channels != 0) {
588 automation_items.push_back (SeparatorElem());
590 /* these 2 MIDI "command" types are semantically more like automation
591 than note data, but they are not MIDI controllers. We give them
592 special status in this menu, since they will not show up in the
593 controller list and anyone who actually knows something about MIDI
594 (!) would not expect to find them there.
597 add_channel_command_menu_item (
598 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
599 automation_items.back().set_sensitive (
600 !for_selection || _editor.get_selection().tracks.size() == 1);
601 add_channel_command_menu_item (
602 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
603 automation_items.back().set_sensitive (
604 !for_selection || _editor.get_selection().tracks.size() == 1);
606 /* now all MIDI controllers. Always offer the possibility that we will
607 rebuild the controllers menu since it might need to be updated after
608 a channel mode change or other change. Also detach it first in case
609 it has been used anywhere else.
612 build_controller_menu ();
614 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
616 if (!poly_pressure_menu) {
617 poly_pressure_menu = new Gtk::Menu;
620 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
622 automation_items.back().set_sensitive (
623 !for_selection || _editor.get_selection().tracks.size() == 1);
625 automation_items.push_back (
626 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
627 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
632 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
634 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
636 for (uint8_t chn = 0; chn < 16; chn++) {
637 if (selected_channels & (0x0001 << chn)) {
639 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
640 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
643 menu->set_active (yn);
650 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
652 AutomationType auto_type,
655 using namespace Menu_Helpers;
657 /* count the number of selected channels because we will build a different menu
658 structure if there is more than 1 selected.
661 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
664 for (uint8_t chn = 0; chn < 16; chn++) {
665 if (selected_channels & (0x0001 << chn)) {
674 /* multiple channels - create a submenu, with 1 item per channel */
676 Menu* chn_menu = manage (new Menu);
677 MenuList& chn_items (chn_menu->items());
678 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
680 /* add a couple of items to hide/show all of them */
682 chn_items.push_back (
683 MenuElem (_("Hide all channels"),
684 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
685 false, param_without_channel)));
686 chn_items.push_back (
687 MenuElem (_("Show all channels"),
688 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
689 true, param_without_channel)));
691 for (uint8_t chn = 0; chn < 16; chn++) {
692 if (selected_channels & (0x0001 << chn)) {
694 /* for each selected channel, add a menu item for this controller */
696 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
697 chn_items.push_back (
698 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
699 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
700 fully_qualified_param)));
702 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
703 bool visible = false;
706 if (track->marked_for_display()) {
711 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
712 _channel_command_menu_map[fully_qualified_param] = cmi;
713 cmi->set_active (visible);
717 /* now create an item in the parent menu that has the per-channel list as a submenu */
719 items.push_back (MenuElem (label, *chn_menu));
723 /* just one channel - create a single menu item for this command+channel combination*/
725 for (uint8_t chn = 0; chn < 16; chn++) {
726 if (selected_channels & (0x0001 << chn)) {
728 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
730 CheckMenuElem (label,
731 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
732 fully_qualified_param)));
734 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
735 bool visible = false;
738 if (track->marked_for_display()) {
743 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
744 _channel_command_menu_map[fully_qualified_param] = cmi;
745 cmi->set_active (visible);
747 /* one channel only */
754 /** Add a single menu item for a controller on one channel. */
756 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
758 const std::string& name)
760 using namespace Menu_Helpers;
762 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
763 for (uint8_t chn = 0; chn < 16; chn++) {
764 if (selected_channels & (0x0001 << chn)) {
766 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
767 ctl_items.push_back (
769 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
771 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
772 fully_qualified_param)));
773 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
775 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
776 fully_qualified_param);
778 bool visible = false;
780 if (track->marked_for_display()) {
785 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
786 _controller_menu_map[fully_qualified_param] = cmi;
787 cmi->set_active (visible);
789 /* one channel only */
795 /** Add a submenu with 1 item per channel for a controller on many channels. */
797 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
799 const std::string& name)
801 using namespace Menu_Helpers;
803 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
805 Menu* chn_menu = manage (new Menu);
806 MenuList& chn_items (chn_menu->items());
808 /* add a couple of items to hide/show this controller on all channels */
810 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
811 chn_items.push_back (
812 MenuElem (_("Hide all channels"),
813 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
814 false, param_without_channel)));
815 chn_items.push_back (
816 MenuElem (_("Show all channels"),
817 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
818 true, param_without_channel)));
820 for (uint8_t chn = 0; chn < 16; chn++) {
821 if (selected_channels & (0x0001 << chn)) {
823 /* for each selected channel, add a menu item for this controller */
825 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
826 chn_items.push_back (
827 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
828 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
829 fully_qualified_param)));
831 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
832 fully_qualified_param);
833 bool visible = false;
836 if (track->marked_for_display()) {
841 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
842 _controller_menu_map[fully_qualified_param] = cmi;
843 cmi->set_active (visible);
847 /* add the per-channel menu to the list of controllers, with the name of the controller */
848 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
850 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
853 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
854 MidiTimeAxisView::get_device_mode()
856 using namespace MIDI::Name;
858 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
860 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
863 return device_names->custom_device_mode_by_name(
864 gui_property (X_("midnam-custom-device-mode")));
867 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
868 MidiTimeAxisView::get_device_names()
870 using namespace MIDI::Name;
872 const std::string model = gui_property (X_("midnam-model-name"));
874 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
875 .document_by_model(model);
877 return midnam->master_device_names(model);
879 return boost::shared_ptr<MasterDeviceNames>();
884 MidiTimeAxisView::build_controller_menu ()
886 using namespace Menu_Helpers;
888 if (controller_menu) {
889 /* it exists and has not been invalidated by a channel mode change */
893 controller_menu = new Menu; // explicitly managed by us
894 MenuList& items (controller_menu->items());
896 /* create several "top level" menu items for sets of controllers (16 at a
897 time), and populate each one with a submenu for each controller+channel
898 combination covering the currently selected channels for this track
901 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
903 /* count the number of selected channels because we will build a different menu
904 structure if there is more than 1 selected.
908 for (uint8_t chn = 0; chn < 16; chn++) {
909 if (selected_channels & (0x0001 << chn)) {
916 using namespace MIDI::Name;
917 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
919 if (device_names && !device_names->controls().empty()) {
920 /* Controllers names available in midnam file, generate fancy menu */
921 unsigned n_items = 0;
922 unsigned n_groups = 0;
924 /* keep track of CC numbers that are added */
925 uint16_t ctl_start = 1;
926 uint16_t ctl_end = 1;
928 MasterDeviceNames::ControlNameLists const& ctllist (device_names->controls());
930 size_t total_ctrls = 0;
931 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
932 boost::shared_ptr<ControlNameList> name_list = l->second;
933 total_ctrls += name_list->controls().size();
936 bool to_top_level = total_ctrls < 32;
938 /* TODO: This is not correct, should look up the currently applicable ControlNameList
939 and only build a menu for that one. */
940 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
941 boost::shared_ptr<ControlNameList> name_list = l->second;
942 Menu* ctl_menu = NULL;
944 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
945 c != name_list->controls().end();) {
946 const uint16_t ctl = c->second->number();
948 /* Skip bank select controllers since they're handled specially */
949 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
952 ctl_menu = controller_menu;
953 } else if (!ctl_menu) {
954 /* Create a new submenu */
955 ctl_menu = manage (new Menu);
959 MenuList& ctl_items (ctl_menu->items());
961 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
963 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
970 if (!ctl_menu || to_top_level) {
974 if (++n_items == 32 || ctl < ctl_start || c == name_list->controls().end()) {
975 /* Submenu has 32 items or we're done, or a new name-list started:
976 * add it to controller menu and reset */
977 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), ctl_start, ctl_end), *ctl_menu));
985 /* No controllers names, generate generic numeric menu */
986 for (int i = 0; i < 127; i += 32) {
987 Menu* ctl_menu = manage (new Menu);
988 MenuList& ctl_items (ctl_menu->items());
990 for (int ctl = i; ctl < i + 32; ++ctl) {
991 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
992 /* Skip bank select controllers since they're handled specially */
997 add_multi_channel_controller_item(
998 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1000 add_single_channel_controller_item(
1001 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1005 /* Add submenu for this block of controllers to controller menu */
1009 /* skip 0x00 and 0x20 (bank-select) */
1010 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i + 1, i + 31), *ctl_menu));
1013 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i + 31), *ctl_menu));
1021 MidiTimeAxisView::build_note_mode_menu()
1023 using namespace Menu_Helpers;
1025 Menu* mode_menu = manage (new Menu);
1026 MenuList& items = mode_menu->items();
1027 mode_menu->set_name ("ArdourContextMenu");
1029 RadioMenuItem::Group mode_group;
1031 RadioMenuElem (mode_group,_("Sustained"),
1032 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1034 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1035 _note_mode_item->set_active(_note_mode == Sustained);
1038 RadioMenuElem (mode_group, _("Percussive"),
1039 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1040 Percussive, true)));
1041 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1042 _percussion_mode_item->set_active(_note_mode == Percussive);
1048 MidiTimeAxisView::build_color_mode_menu()
1050 using namespace Menu_Helpers;
1052 Menu* mode_menu = manage (new Menu);
1053 MenuList& items = mode_menu->items();
1054 mode_menu->set_name ("ArdourContextMenu");
1056 RadioMenuItem::Group mode_group;
1058 RadioMenuElem (mode_group, _("Meter Colors"),
1059 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1060 MeterColors, false, true, true)));
1061 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1062 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1065 RadioMenuElem (mode_group, _("Channel Colors"),
1066 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1067 ChannelColors, false, true, true)));
1068 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1069 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1072 RadioMenuElem (mode_group, _("Track Color"),
1073 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1074 TrackColor, false, true, true)));
1075 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1076 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1082 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1084 if (apply_to_selection) {
1085 _editor.get_selection().tracks.foreach_midi_time_axis (
1086 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1088 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1090 midi_track()->set_note_mode(mode);
1091 set_gui_property ("note-mode", enum_2_string(_note_mode));
1092 _view->redisplay_track();
1098 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1100 if (apply_to_selection) {
1101 _editor.get_selection().tracks.foreach_midi_time_axis (
1102 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1104 if (_color_mode == mode && !force) {
1108 if (_channel_selector) {
1109 if (mode == ChannelColors) {
1110 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1112 _channel_selector->set_default_channel_color();
1117 set_gui_property ("color-mode", enum_2_string(_color_mode));
1119 _view->redisplay_track();
1125 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1127 if (apply_to_selection) {
1128 _editor.get_selection().tracks.foreach_midi_time_axis (
1129 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1131 if (!_ignore_signals) {
1132 midi_view()->set_note_range(range);
1138 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1140 using namespace MIDI::Name;
1142 if (apply_to_selection) {
1143 _editor.get_selection().tracks.foreach_midi_time_axis (
1144 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1147 // Show existing automation
1148 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1150 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1151 create_automation_child(*i, true);
1154 // Show automation for all controllers named in midnam file
1155 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1156 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1157 device_names && !device_names->controls().empty()) {
1158 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1159 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1160 for (uint32_t chn = 0; chn < 16; ++chn) {
1161 if ((selected_channels & (0x0001 << chn)) == 0) {
1162 // Channel not in use
1166 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1172 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1173 chan_names->control_list_name());
1174 if (!control_names) {
1178 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1179 c != control_names->controls().end();
1181 const uint16_t ctl = c->second->number();
1182 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1183 /* Skip bank select controllers since they're handled specially */
1184 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1185 create_automation_child(param, true);
1192 RouteTimeAxisView::show_all_automation ();
1197 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1199 if (apply_to_selection) {
1200 _editor.get_selection().tracks.foreach_midi_time_axis (
1201 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1204 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1206 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1207 create_automation_child (*i, true);
1211 RouteTimeAxisView::show_existing_automation ();
1215 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1218 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1220 if (param.type() == NullAutomation) {
1224 AutomationTracks::iterator existing = _automation_tracks.find (param);
1226 if (existing != _automation_tracks.end()) {
1228 /* automation track created because we had existing data for
1229 * the processor, but visibility may need to be controlled
1230 * since it will have been set visible by default.
1233 existing->second->set_marked_for_display (show);
1242 boost::shared_ptr<AutomationTimeAxisView> track;
1243 boost::shared_ptr<AutomationControl> control;
1246 switch (param.type()) {
1248 case GainAutomation:
1249 create_gain_automation_child (param, show);
1252 case MuteAutomation:
1253 create_mute_automation_child (param, show);
1256 case PluginAutomation:
1257 /* handled elsewhere */
1260 case MidiCCAutomation:
1261 case MidiPgmChangeAutomation:
1262 case MidiPitchBenderAutomation:
1263 case MidiChannelPressureAutomation:
1264 case MidiSystemExclusiveAutomation:
1265 /* These controllers are region "automation" - they are owned
1266 * by regions (and their MidiModels), not by the track. As a
1267 * result there is no AutomationList/Line for the track, but we create
1268 * a controller for the user to write immediate events, so the editor
1269 * can act as a control surface for the present MIDI controllers.
1271 * TODO: Record manipulation of the controller to regions?
1274 control = _route->automation_control(param, true);
1275 track.reset (new AutomationTimeAxisView (
1278 control ? _route : boost::shared_ptr<Automatable> (),
1285 _route->describe_parameter(param)));
1288 _view->foreach_regionview (
1289 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1292 add_automation_child (param, track, show);
1294 reshow_selection (_editor.get_selection().time);
1299 case PanWidthAutomation:
1300 case PanElevationAutomation:
1301 case PanAzimuthAutomation:
1302 ensure_pan_views (show);
1306 error << "MidiTimeAxisView: unknown automation child "
1307 << EventTypeMap::instance().to_symbol(param) << endmsg;
1312 MidiTimeAxisView::route_active_changed ()
1314 RouteUI::route_active_changed ();
1315 update_control_names();
1319 MidiTimeAxisView::update_control_names ()
1322 if (_route->active()) {
1323 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1324 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1326 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1327 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1329 } else { // MIDI bus (which doesn't exist yet..)
1330 if (_route->active()) {
1331 controls_base_selected_name = "BusControlsBaseSelected";
1332 controls_base_unselected_name = "BusControlsBaseUnselected";
1334 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1335 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1340 controls_ebox.set_name (controls_base_selected_name);
1341 time_axis_frame.set_name (controls_base_selected_name);
1343 controls_ebox.set_name (controls_base_unselected_name);
1344 time_axis_frame.set_name (controls_base_unselected_name);
1349 MidiTimeAxisView::set_note_selection (uint8_t note)
1351 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1353 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1355 if (_view->num_selected_regionviews() == 0) {
1356 _view->foreach_regionview (
1357 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1360 _view->foreach_selected_regionview (
1361 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1365 _editor.commit_reversible_selection_op();
1369 MidiTimeAxisView::add_note_selection (uint8_t note)
1371 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1373 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1375 if (_view->num_selected_regionviews() == 0) {
1376 _view->foreach_regionview (
1377 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1380 _view->foreach_selected_regionview (
1381 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1385 _editor.commit_reversible_selection_op();
1389 MidiTimeAxisView::extend_note_selection (uint8_t note)
1391 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1393 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1395 if (_view->num_selected_regionviews() == 0) {
1396 _view->foreach_regionview (
1397 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1400 _view->foreach_selected_regionview (
1401 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1405 _editor.commit_reversible_selection_op();
1409 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1411 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1413 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1415 if (_view->num_selected_regionviews() == 0) {
1416 _view->foreach_regionview (
1417 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1420 _view->foreach_selected_regionview (
1421 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1425 _editor.commit_reversible_selection_op();
1429 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > >& selection)
1431 _view->foreach_regionview (
1432 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1436 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1438 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1442 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1444 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1448 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1450 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1454 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1456 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1460 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection)
1462 Evoral::Sequence<Temporal::Beats>::Notes selected;
1463 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1465 std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > notes;
1467 Evoral::Sequence<Temporal::Beats>::Notes::iterator sel_it;
1468 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1469 notes.insert (*sel_it);
1472 if (!notes.empty()) {
1473 selection.push_back (make_pair ((rv)->region()->id(), notes));
1478 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1480 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1484 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1485 bool changed = false;
1489 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1491 for (uint32_t chn = 0; chn < 16; ++chn) {
1492 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1493 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1499 if ((selected_channels & (0x0001 << chn)) == 0) {
1500 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1501 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1503 changed = track->set_marked_for_display (false) || changed;
1505 changed = track->set_marked_for_display (true) || changed;
1512 /* TODO: Bender, Pressure */
1514 /* invalidate the controller menu, so that we rebuild it next time */
1515 _controller_menu_map.clear ();
1516 delete controller_menu;
1517 controller_menu = 0;
1525 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1527 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1532 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1533 if (i != _controller_menu_map.end()) {
1537 i = _channel_command_menu_map.find (param);
1538 if (i != _channel_command_menu_map.end()) {
1545 boost::shared_ptr<MidiRegion>
1546 MidiTimeAxisView::add_region (samplepos_t f, samplecnt_t length, bool commit)
1548 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1549 MusicSample pos (f, 0);
1552 real_editor->begin_reversible_command (Operations::create_region);
1554 playlist()->clear_changes ();
1556 real_editor->snap_to (pos, RoundNearest);
1558 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1561 plist.add (ARDOUR::Properties::start, 0);
1562 plist.add (ARDOUR::Properties::length, length);
1563 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1565 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1566 /* sets beat position */
1567 region->set_position (pos.sample, pos.division);
1568 playlist()->add_region (region, pos.sample, 1.0, false, pos.division);
1569 _session->add_command (new StatefulDiffCommand (playlist()));
1572 real_editor->commit_reversible_command ();
1575 return boost::dynamic_pointer_cast<MidiRegion>(region);
1579 MidiTimeAxisView::ensure_step_editor ()
1581 if (!_step_editor) {
1582 _step_editor = new StepEditor (_editor, midi_track(), *this);
1587 MidiTimeAxisView::start_step_editing ()
1589 ensure_step_editor ();
1590 _step_editor->start_step_editing ();
1594 MidiTimeAxisView::stop_step_editing ()
1597 _step_editor->stop_step_editing ();
1601 /** @return channel (counted from 0) to add an event to, based on the current setting
1602 * of the channel selector.
1605 MidiTimeAxisView::get_channel_for_add () const
1607 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1609 uint8_t channel = 0;
1611 /* pick the highest selected channel, unless all channels are selected,
1612 which is interpreted to mean channel 1 (zero)
1615 for (uint16_t i = 0; i < 16; ++i) {
1616 if (chn_mask & (1<<i)) {
1622 if (chn_cnt == 16) {
1630 MidiTimeAxisView::note_range_changed ()
1632 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1633 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1637 MidiTimeAxisView::contents_height_changed ()
1639 _range_scroomer->queue_resize ();
1643 MidiTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1645 if (!_editor.internal_editing()) {
1646 // Non-internal paste, paste regions like any other route
1647 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1650 return midi_view()->paste(pos, selection, ctx, sub_num);