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 if (!gui_property ("note-range-min").empty ()) {
162 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
163 atoi (gui_property ("note-range-max").c_str()),
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 ());
196 _piano_roll_header->SetNoteSelection.connect (
197 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
198 _piano_roll_header->AddNoteSelection.connect (
199 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
200 _piano_roll_header->ExtendNoteSelection.connect (
201 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
202 _piano_roll_header->ToggleNoteSelection.connect (
203 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
205 /* Update StreamView during scroomer drags.*/
207 _range_scroomer->DragStarting.connect (
208 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
209 _range_scroomer->DragFinishing.connect (
210 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
212 /* Put the scroomer and the keyboard in a VBox with a padding
213 label so that they can be reduced in height for stacked-view
217 HSeparator* separator = manage (new HSeparator());
218 separator->set_name("TrackSeparator");
219 separator->set_size_request(-1, 1);
222 VBox* v = manage (new VBox);
223 HBox* h = manage (new HBox);
224 h->pack_end (*_piano_roll_header);
225 h->pack_end (*_range_scroomer);
226 v->pack_start (*separator, false, false);
227 v->pack_start (*h, true, true);
230 top_hbox.remove(scroomer_placeholder);
231 time_axis_hbox.pack_end(*v, false, false, 0);
232 midi_scroomer_size_group->add_widget (*v);
234 midi_view()->NoteRangeChanged.connect (
235 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
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::start_scroomer_update ()
389 _note_range_changed_connection.disconnect();
390 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
391 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
394 MidiTimeAxisView::stop_scroomer_update ()
396 _note_range_changed_connection.disconnect();
400 MidiTimeAxisView::update_patch_selector ()
402 typedef MIDI::Name::MidiPatchManager PatchManager;
403 PatchManager& patch_manager = PatchManager::instance();
405 bool pluginprovided = false;
407 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
408 if (pi && pi->plugin ()->has_midnam ()) {
409 pluginprovided = true;
410 std::string model_name = pi->plugin ()->midnam_model ();
411 if (gui_property (X_("midnam-model-name")) != model_name) {
412 model_changed (model_name);
417 if (patch_manager.all_models().empty() || pluginprovided) {
418 _midnam_model_selector.hide ();
419 _midnam_custom_device_mode_selector.hide ();
421 _midnam_model_selector.show ();
422 _midnam_custom_device_mode_selector.show ();
428 MidiTimeAxisView::model_changed(const std::string& model)
430 set_gui_property (X_("midnam-model-name"), model);
432 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
433 .custom_device_mode_names_by_model(model);
435 _midnam_model_selector.set_text(model);
436 _midnam_custom_device_mode_selector.clear_items();
438 for (std::list<std::string>::const_iterator i = device_modes.begin();
439 i != device_modes.end(); ++i) {
440 _midnam_custom_device_mode_selector.AddMenuElem(
441 Gtk::Menu_Helpers::MenuElem(
442 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
446 if (!device_modes.empty()) {
447 custom_device_mode_changed(device_modes.front());
450 if (device_modes.size() > 1) {
451 _midnam_custom_device_mode_selector.show();
453 _midnam_custom_device_mode_selector.hide();
456 // now this is a real bad hack
457 if (device_modes.size() > 0) {
458 _route->instrument_info().set_external_instrument (model, device_modes.front());
460 _route->instrument_info().set_external_instrument (model, "");
463 // Rebuild controller menu
464 _controller_menu_map.clear ();
465 delete controller_menu;
467 build_automation_action_menu(false);
469 if (patch_change_dialog ()) {
470 patch_change_dialog ()->refresh ();
475 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
477 const std::string model = gui_property (X_("midnam-model-name"));
479 set_gui_property (X_("midnam-custom-device-mode"), mode);
480 _midnam_custom_device_mode_selector.set_text(mode);
481 _route->instrument_info().set_external_instrument (model, mode);
485 MidiTimeAxisView::midi_view()
487 return dynamic_cast<MidiStreamView*>(_view);
491 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
493 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
494 _midi_controls_box.show ();
496 _midi_controls_box.hide();
499 if (h >= KEYBOARD_MIN_HEIGHT) {
500 if (is_track() && _range_scroomer) {
501 _range_scroomer->show();
503 if (is_track() && _piano_roll_header) {
504 _piano_roll_header->show();
507 if (is_track() && _range_scroomer) {
508 _range_scroomer->hide();
510 if (is_track() && _piano_roll_header) {
511 _piano_roll_header->hide();
515 /* We need to do this after changing visibility of our stuff, as it will
516 eventually trigger a call to Editor::reset_controls_layout_width(),
517 which needs to know if we have just shown or hidden a scroomer /
520 RouteTimeAxisView::set_height (h, m);
524 MidiTimeAxisView::append_extra_display_menu_items ()
526 using namespace Menu_Helpers;
528 MenuList& items = display_menu->items();
531 Menu *range_menu = manage(new Menu);
532 MenuList& range_items = range_menu->items();
533 range_menu->set_name ("ArdourContextMenu");
535 range_items.push_back (
536 MenuElem (_("Show Full Range"),
537 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
538 MidiStreamView::FullRange, true)));
540 range_items.push_back (
541 MenuElem (_("Fit Contents"),
542 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
543 MidiStreamView::ContentsRange, true)));
545 items.push_back (MenuElem (_("Note Range"), *range_menu));
546 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
547 items.push_back (MenuElem (_("Channel Selector..."),
548 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
550 items.push_back (MenuElem (_("Patch Selector..."),
551 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
553 items.push_back (MenuElem (_("Color Mode"), *build_color_mode_menu ()));
555 items.push_back (SeparatorElem ());
559 MidiTimeAxisView::toggle_channel_selector ()
561 if (!_channel_selector) {
562 _channel_selector = new MidiChannelSelectorWindow (midi_track());
564 if (_color_mode == ChannelColors) {
565 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
567 _channel_selector->set_default_channel_color ();
570 _channel_selector->show_all ();
572 _channel_selector->cycle_visibility ();
577 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
579 using namespace Menu_Helpers;
581 /* If we have a controller menu, we need to detach it before
582 RouteTimeAxis::build_automation_action_menu destroys the
583 menu it is attached to. Otherwise GTK destroys
584 controller_menu's gobj, meaning that it can't be reattached
585 below. See bug #3134.
588 if (controller_menu) {
589 detach_menu (*controller_menu);
592 _channel_command_menu_map.clear ();
593 RouteTimeAxisView::build_automation_action_menu (for_selection);
595 MenuList& automation_items = automation_action_menu->items();
597 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
599 if (selected_channels != 0) {
601 automation_items.push_back (SeparatorElem());
603 /* these 2 MIDI "command" types are semantically more like automation
604 than note data, but they are not MIDI controllers. We give them
605 special status in this menu, since they will not show up in the
606 controller list and anyone who actually knows something about MIDI
607 (!) would not expect to find them there.
610 add_channel_command_menu_item (
611 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
612 automation_items.back().set_sensitive (
613 !for_selection || _editor.get_selection().tracks.size() == 1);
614 add_channel_command_menu_item (
615 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
616 automation_items.back().set_sensitive (
617 !for_selection || _editor.get_selection().tracks.size() == 1);
619 /* now all MIDI controllers. Always offer the possibility that we will
620 rebuild the controllers menu since it might need to be updated after
621 a channel mode change or other change. Also detach it first in case
622 it has been used anywhere else.
625 build_controller_menu ();
627 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
629 if (!poly_pressure_menu) {
630 poly_pressure_menu = new Gtk::Menu;
633 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
635 automation_items.back().set_sensitive (
636 !for_selection || _editor.get_selection().tracks.size() == 1);
638 automation_items.push_back (
639 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
640 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
645 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
647 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
649 for (uint8_t chn = 0; chn < 16; chn++) {
650 if (selected_channels & (0x0001 << chn)) {
652 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
653 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
656 menu->set_active (yn);
663 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
665 AutomationType auto_type,
668 using namespace Menu_Helpers;
670 /* count the number of selected channels because we will build a different menu
671 structure if there is more than 1 selected.
674 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
677 for (uint8_t chn = 0; chn < 16; chn++) {
678 if (selected_channels & (0x0001 << chn)) {
687 /* multiple channels - create a submenu, with 1 item per channel */
689 Menu* chn_menu = manage (new Menu);
690 MenuList& chn_items (chn_menu->items());
691 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
693 /* add a couple of items to hide/show all of them */
695 chn_items.push_back (
696 MenuElem (_("Hide all channels"),
697 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
698 false, param_without_channel)));
699 chn_items.push_back (
700 MenuElem (_("Show all channels"),
701 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
702 true, param_without_channel)));
704 for (uint8_t chn = 0; chn < 16; chn++) {
705 if (selected_channels & (0x0001 << chn)) {
707 /* for each selected channel, add a menu item for this controller */
709 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
710 chn_items.push_back (
711 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
712 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
713 fully_qualified_param)));
715 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
716 bool visible = false;
719 if (track->marked_for_display()) {
724 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
725 _channel_command_menu_map[fully_qualified_param] = cmi;
726 cmi->set_active (visible);
730 /* now create an item in the parent menu that has the per-channel list as a submenu */
732 items.push_back (MenuElem (label, *chn_menu));
736 /* just one channel - create a single menu item for this command+channel combination*/
738 for (uint8_t chn = 0; chn < 16; chn++) {
739 if (selected_channels & (0x0001 << chn)) {
741 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
743 CheckMenuElem (label,
744 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
745 fully_qualified_param)));
747 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
748 bool visible = false;
751 if (track->marked_for_display()) {
756 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
757 _channel_command_menu_map[fully_qualified_param] = cmi;
758 cmi->set_active (visible);
760 /* one channel only */
767 /** Add a single menu item for a controller on one channel. */
769 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
771 const std::string& name)
773 using namespace Menu_Helpers;
775 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
776 for (uint8_t chn = 0; chn < 16; chn++) {
777 if (selected_channels & (0x0001 << chn)) {
779 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
780 ctl_items.push_back (
782 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
784 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
785 fully_qualified_param)));
786 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
788 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
789 fully_qualified_param);
791 bool visible = false;
793 if (track->marked_for_display()) {
798 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
799 _controller_menu_map[fully_qualified_param] = cmi;
800 cmi->set_active (visible);
802 /* one channel only */
808 /** Add a submenu with 1 item per channel for a controller on many channels. */
810 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
812 const std::string& name)
814 using namespace Menu_Helpers;
816 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
818 Menu* chn_menu = manage (new Menu);
819 MenuList& chn_items (chn_menu->items());
821 /* add a couple of items to hide/show this controller on all channels */
823 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
824 chn_items.push_back (
825 MenuElem (_("Hide all channels"),
826 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
827 false, param_without_channel)));
828 chn_items.push_back (
829 MenuElem (_("Show all channels"),
830 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
831 true, param_without_channel)));
833 for (uint8_t chn = 0; chn < 16; chn++) {
834 if (selected_channels & (0x0001 << chn)) {
836 /* for each selected channel, add a menu item for this controller */
838 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
839 chn_items.push_back (
840 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
841 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
842 fully_qualified_param)));
844 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
845 fully_qualified_param);
846 bool visible = false;
849 if (track->marked_for_display()) {
854 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
855 _controller_menu_map[fully_qualified_param] = cmi;
856 cmi->set_active (visible);
860 /* add the per-channel menu to the list of controllers, with the name of the controller */
861 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
863 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
866 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
867 MidiTimeAxisView::get_device_mode()
869 using namespace MIDI::Name;
871 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
873 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
876 return device_names->custom_device_mode_by_name(
877 gui_property (X_("midnam-custom-device-mode")));
880 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
881 MidiTimeAxisView::get_device_names()
883 using namespace MIDI::Name;
885 const std::string model = gui_property (X_("midnam-model-name"));
887 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
888 .document_by_model(model);
890 return midnam->master_device_names(model);
892 return boost::shared_ptr<MasterDeviceNames>();
897 MidiTimeAxisView::build_controller_menu ()
899 using namespace Menu_Helpers;
901 if (controller_menu) {
902 /* it exists and has not been invalidated by a channel mode change */
906 controller_menu = new Menu; // explicitly managed by us
907 MenuList& items (controller_menu->items());
909 /* create several "top level" menu items for sets of controllers (16 at a
910 time), and populate each one with a submenu for each controller+channel
911 combination covering the currently selected channels for this track
914 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
916 /* count the number of selected channels because we will build a different menu
917 structure if there is more than 1 selected.
921 for (uint8_t chn = 0; chn < 16; chn++) {
922 if (selected_channels & (0x0001 << chn)) {
929 using namespace MIDI::Name;
930 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
932 if (device_names && !device_names->controls().empty()) {
933 /* Controllers names available in midnam file, generate fancy menu */
934 unsigned n_items = 0;
935 unsigned n_groups = 0;
937 /* TODO: This is not correct, should look up the currently applicable ControlNameList
938 and only build a menu for that one. */
939 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
940 l != device_names->controls().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();
947 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
948 /* Skip bank select controllers since they're handled specially */
950 /* Create a new submenu */
951 ctl_menu = manage (new Menu);
954 MenuList& ctl_items (ctl_menu->items());
956 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
958 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
963 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
964 /* Submenu has 16 items or we're done, add it to controller menu and reset */
966 MenuElem(string_compose(_("Controllers %1-%2"),
967 (16 * n_groups), (16 * n_groups) + n_items - 1),
976 /* No controllers names, generate generic numeric menu */
977 for (int i = 0; i < 127; i += 16) {
978 Menu* ctl_menu = manage (new Menu);
979 MenuList& ctl_items (ctl_menu->items());
981 for (int ctl = i; ctl < i+16; ++ctl) {
982 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
983 /* Skip bank select controllers since they're handled specially */
988 add_multi_channel_controller_item(
989 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
991 add_single_channel_controller_item(
992 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
996 /* Add submenu for this block of controllers to controller menu */
998 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1005 MidiTimeAxisView::build_note_mode_menu()
1007 using namespace Menu_Helpers;
1009 Menu* mode_menu = manage (new Menu);
1010 MenuList& items = mode_menu->items();
1011 mode_menu->set_name ("ArdourContextMenu");
1013 RadioMenuItem::Group mode_group;
1015 RadioMenuElem (mode_group,_("Sustained"),
1016 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1018 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1019 _note_mode_item->set_active(_note_mode == Sustained);
1022 RadioMenuElem (mode_group, _("Percussive"),
1023 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1024 Percussive, true)));
1025 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1026 _percussion_mode_item->set_active(_note_mode == Percussive);
1032 MidiTimeAxisView::build_color_mode_menu()
1034 using namespace Menu_Helpers;
1036 Menu* mode_menu = manage (new Menu);
1037 MenuList& items = mode_menu->items();
1038 mode_menu->set_name ("ArdourContextMenu");
1040 RadioMenuItem::Group mode_group;
1042 RadioMenuElem (mode_group, _("Meter Colors"),
1043 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1044 MeterColors, false, true, true)));
1045 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1046 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1049 RadioMenuElem (mode_group, _("Channel Colors"),
1050 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1051 ChannelColors, false, true, true)));
1052 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1053 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1056 RadioMenuElem (mode_group, _("Track Color"),
1057 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1058 TrackColor, false, true, true)));
1059 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1060 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1066 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1068 if (apply_to_selection) {
1069 _editor.get_selection().tracks.foreach_midi_time_axis (
1070 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1072 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1074 midi_track()->set_note_mode(mode);
1075 set_gui_property ("note-mode", enum_2_string(_note_mode));
1076 _view->redisplay_track();
1082 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1084 if (apply_to_selection) {
1085 _editor.get_selection().tracks.foreach_midi_time_axis (
1086 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1088 if (_color_mode == mode && !force) {
1092 if (_channel_selector) {
1093 if (mode == ChannelColors) {
1094 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1096 _channel_selector->set_default_channel_color();
1101 set_gui_property ("color-mode", enum_2_string(_color_mode));
1103 _view->redisplay_track();
1109 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1111 if (apply_to_selection) {
1112 _editor.get_selection().tracks.foreach_midi_time_axis (
1113 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1115 if (!_ignore_signals) {
1116 midi_view()->set_note_range(range);
1122 MidiTimeAxisView::update_range()
1127 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1129 using namespace MIDI::Name;
1131 if (apply_to_selection) {
1132 _editor.get_selection().tracks.foreach_midi_time_axis (
1133 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1136 // Show existing automation
1137 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1139 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1140 create_automation_child(*i, true);
1143 // Show automation for all controllers named in midnam file
1144 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1145 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1146 device_names && !device_names->controls().empty()) {
1147 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1148 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1149 for (uint32_t chn = 0; chn < 16; ++chn) {
1150 if ((selected_channels & (0x0001 << chn)) == 0) {
1151 // Channel not in use
1155 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1161 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1162 chan_names->control_list_name());
1163 if (!control_names) {
1167 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1168 c != control_names->controls().end();
1170 const uint16_t ctl = c->second->number();
1171 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1172 /* Skip bank select controllers since they're handled specially */
1173 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1174 create_automation_child(param, true);
1181 RouteTimeAxisView::show_all_automation ();
1186 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1188 if (apply_to_selection) {
1189 _editor.get_selection().tracks.foreach_midi_time_axis (
1190 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1193 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1195 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1196 create_automation_child (*i, true);
1200 RouteTimeAxisView::show_existing_automation ();
1204 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1207 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1209 if (param.type() == NullAutomation) {
1213 AutomationTracks::iterator existing = _automation_tracks.find (param);
1215 if (existing != _automation_tracks.end()) {
1217 /* automation track created because we had existing data for
1218 * the processor, but visibility may need to be controlled
1219 * since it will have been set visible by default.
1222 existing->second->set_marked_for_display (show);
1231 boost::shared_ptr<AutomationTimeAxisView> track;
1232 boost::shared_ptr<AutomationControl> control;
1235 switch (param.type()) {
1237 case GainAutomation:
1238 create_gain_automation_child (param, show);
1241 case MuteAutomation:
1242 create_mute_automation_child (param, show);
1245 case PluginAutomation:
1246 /* handled elsewhere */
1249 case MidiCCAutomation:
1250 case MidiPgmChangeAutomation:
1251 case MidiPitchBenderAutomation:
1252 case MidiChannelPressureAutomation:
1253 case MidiSystemExclusiveAutomation:
1254 /* These controllers are region "automation" - they are owned
1255 * by regions (and their MidiModels), not by the track. As a
1256 * result there is no AutomationList/Line for the track, but we create
1257 * a controller for the user to write immediate events, so the editor
1258 * can act as a control surface for the present MIDI controllers.
1260 * TODO: Record manipulation of the controller to regions?
1263 control = _route->automation_control(param, true);
1264 track.reset (new AutomationTimeAxisView (
1267 control ? _route : boost::shared_ptr<Automatable> (),
1274 _route->describe_parameter(param)));
1277 _view->foreach_regionview (
1278 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1281 add_automation_child (param, track, show);
1283 reshow_selection (_editor.get_selection().time);
1288 case PanWidthAutomation:
1289 case PanElevationAutomation:
1290 case PanAzimuthAutomation:
1291 ensure_pan_views (show);
1295 error << "MidiTimeAxisView: unknown automation child "
1296 << EventTypeMap::instance().to_symbol(param) << endmsg;
1301 MidiTimeAxisView::route_active_changed ()
1303 RouteUI::route_active_changed ();
1304 update_control_names();
1308 MidiTimeAxisView::update_control_names ()
1311 if (_route->active()) {
1312 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1313 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1315 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1316 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1318 } else { // MIDI bus (which doesn't exist yet..)
1319 if (_route->active()) {
1320 controls_base_selected_name = "BusControlsBaseSelected";
1321 controls_base_unselected_name = "BusControlsBaseUnselected";
1323 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1324 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1329 controls_ebox.set_name (controls_base_selected_name);
1330 time_axis_frame.set_name (controls_base_selected_name);
1332 controls_ebox.set_name (controls_base_unselected_name);
1333 time_axis_frame.set_name (controls_base_unselected_name);
1338 MidiTimeAxisView::set_note_selection (uint8_t note)
1340 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1342 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1344 if (_view->num_selected_regionviews() == 0) {
1345 _view->foreach_regionview (
1346 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1349 _view->foreach_selected_regionview (
1350 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1354 _editor.commit_reversible_selection_op();
1358 MidiTimeAxisView::add_note_selection (uint8_t note)
1360 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1362 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1364 if (_view->num_selected_regionviews() == 0) {
1365 _view->foreach_regionview (
1366 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1369 _view->foreach_selected_regionview (
1370 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1374 _editor.commit_reversible_selection_op();
1378 MidiTimeAxisView::extend_note_selection (uint8_t note)
1380 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1382 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1384 if (_view->num_selected_regionviews() == 0) {
1385 _view->foreach_regionview (
1386 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1389 _view->foreach_selected_regionview (
1390 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1394 _editor.commit_reversible_selection_op();
1398 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1400 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1402 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1404 if (_view->num_selected_regionviews() == 0) {
1405 _view->foreach_regionview (
1406 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1409 _view->foreach_selected_regionview (
1410 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1414 _editor.commit_reversible_selection_op();
1418 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > >& selection)
1420 _view->foreach_regionview (
1421 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1425 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1427 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1431 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1433 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1437 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1439 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1443 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1445 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1449 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection)
1451 Evoral::Sequence<Temporal::Beats>::Notes selected;
1452 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1454 std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > notes;
1456 Evoral::Sequence<Temporal::Beats>::Notes::iterator sel_it;
1457 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1458 notes.insert (*sel_it);
1461 if (!notes.empty()) {
1462 selection.push_back (make_pair ((rv)->region()->id(), notes));
1467 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1469 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1473 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1474 bool changed = false;
1478 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1480 for (uint32_t chn = 0; chn < 16; ++chn) {
1481 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1482 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1488 if ((selected_channels & (0x0001 << chn)) == 0) {
1489 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1490 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1492 changed = track->set_marked_for_display (false) || changed;
1494 changed = track->set_marked_for_display (true) || changed;
1501 /* TODO: Bender, Pressure */
1503 /* invalidate the controller menu, so that we rebuild it next time */
1504 _controller_menu_map.clear ();
1505 delete controller_menu;
1506 controller_menu = 0;
1514 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1516 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1521 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1522 if (i != _controller_menu_map.end()) {
1526 i = _channel_command_menu_map.find (param);
1527 if (i != _channel_command_menu_map.end()) {
1534 boost::shared_ptr<MidiRegion>
1535 MidiTimeAxisView::add_region (samplepos_t f, samplecnt_t length, bool commit)
1537 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1538 MusicSample pos (f, 0);
1541 real_editor->begin_reversible_command (Operations::create_region);
1543 playlist()->clear_changes ();
1545 real_editor->snap_to (pos, RoundNearest);
1547 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1550 plist.add (ARDOUR::Properties::start, 0);
1551 plist.add (ARDOUR::Properties::length, length);
1552 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1554 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1555 /* sets beat position */
1556 region->set_position (pos.sample, pos.division);
1557 playlist()->add_region (region, pos.sample, 1.0, false, pos.division);
1558 _session->add_command (new StatefulDiffCommand (playlist()));
1561 real_editor->commit_reversible_command ();
1564 return boost::dynamic_pointer_cast<MidiRegion>(region);
1568 MidiTimeAxisView::ensure_step_editor ()
1570 if (!_step_editor) {
1571 _step_editor = new StepEditor (_editor, midi_track(), *this);
1576 MidiTimeAxisView::start_step_editing ()
1578 ensure_step_editor ();
1579 _step_editor->start_step_editing ();
1583 MidiTimeAxisView::stop_step_editing ()
1586 _step_editor->stop_step_editing ();
1590 /** @return channel (counted from 0) to add an event to, based on the current setting
1591 * of the channel selector.
1594 MidiTimeAxisView::get_channel_for_add () const
1596 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1598 uint8_t channel = 0;
1600 /* pick the highest selected channel, unless all channels are selected,
1601 which is interpreted to mean channel 1 (zero)
1604 for (uint16_t i = 0; i < 16; ++i) {
1605 if (chn_mask & (1<<i)) {
1611 if (chn_cnt == 16) {
1619 MidiTimeAxisView::note_range_changed ()
1621 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1622 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1626 MidiTimeAxisView::contents_height_changed ()
1628 _range_scroomer->queue_resize ();
1632 MidiTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1634 if (!_editor.internal_editing()) {
1635 // Non-internal paste, paste regions like any other route
1636 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1639 return midi_view()->paste(pos, selection, ctx, sub_num);