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 color_mode_menu = build_color_mode_menu();
554 if (color_mode_menu) {
555 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
558 items.push_back (SeparatorElem ());
562 MidiTimeAxisView::toggle_channel_selector ()
564 if (!_channel_selector) {
565 _channel_selector = new MidiChannelSelectorWindow (midi_track());
567 if (_color_mode == ChannelColors) {
568 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
570 _channel_selector->set_default_channel_color ();
573 _channel_selector->show_all ();
575 _channel_selector->cycle_visibility ();
580 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
582 using namespace Menu_Helpers;
584 /* If we have a controller menu, we need to detach it before
585 RouteTimeAxis::build_automation_action_menu destroys the
586 menu it is attached to. Otherwise GTK destroys
587 controller_menu's gobj, meaning that it can't be reattached
588 below. See bug #3134.
591 if (controller_menu) {
592 detach_menu (*controller_menu);
595 _channel_command_menu_map.clear ();
596 RouteTimeAxisView::build_automation_action_menu (for_selection);
598 MenuList& automation_items = automation_action_menu->items();
600 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
602 if (selected_channels != 0) {
604 automation_items.push_back (SeparatorElem());
606 /* these 2 MIDI "command" types are semantically more like automation
607 than note data, but they are not MIDI controllers. We give them
608 special status in this menu, since they will not show up in the
609 controller list and anyone who actually knows something about MIDI
610 (!) would not expect to find them there.
613 add_channel_command_menu_item (
614 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
615 automation_items.back().set_sensitive (
616 !for_selection || _editor.get_selection().tracks.size() == 1);
617 add_channel_command_menu_item (
618 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
619 automation_items.back().set_sensitive (
620 !for_selection || _editor.get_selection().tracks.size() == 1);
622 /* now all MIDI controllers. Always offer the possibility that we will
623 rebuild the controllers menu since it might need to be updated after
624 a channel mode change or other change. Also detach it first in case
625 it has been used anywhere else.
628 build_controller_menu ();
630 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
632 if (!poly_pressure_menu) {
633 poly_pressure_menu = new Gtk::Menu;
636 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
638 automation_items.back().set_sensitive (
639 !for_selection || _editor.get_selection().tracks.size() == 1);
641 automation_items.push_back (
642 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
643 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
648 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
650 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
652 for (uint8_t chn = 0; chn < 16; chn++) {
653 if (selected_channels & (0x0001 << chn)) {
655 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
656 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
659 menu->set_active (yn);
666 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
668 AutomationType auto_type,
671 using namespace Menu_Helpers;
673 /* count the number of selected channels because we will build a different menu
674 structure if there is more than 1 selected.
677 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
680 for (uint8_t chn = 0; chn < 16; chn++) {
681 if (selected_channels & (0x0001 << chn)) {
690 /* multiple channels - create a submenu, with 1 item per channel */
692 Menu* chn_menu = manage (new Menu);
693 MenuList& chn_items (chn_menu->items());
694 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
696 /* add a couple of items to hide/show all of them */
698 chn_items.push_back (
699 MenuElem (_("Hide all channels"),
700 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
701 false, param_without_channel)));
702 chn_items.push_back (
703 MenuElem (_("Show all channels"),
704 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
705 true, param_without_channel)));
707 for (uint8_t chn = 0; chn < 16; chn++) {
708 if (selected_channels & (0x0001 << chn)) {
710 /* for each selected channel, add a menu item for this controller */
712 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
713 chn_items.push_back (
714 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
715 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
716 fully_qualified_param)));
718 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
719 bool visible = false;
722 if (track->marked_for_display()) {
727 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
728 _channel_command_menu_map[fully_qualified_param] = cmi;
729 cmi->set_active (visible);
733 /* now create an item in the parent menu that has the per-channel list as a submenu */
735 items.push_back (MenuElem (label, *chn_menu));
739 /* just one channel - create a single menu item for this command+channel combination*/
741 for (uint8_t chn = 0; chn < 16; chn++) {
742 if (selected_channels & (0x0001 << chn)) {
744 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
746 CheckMenuElem (label,
747 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
748 fully_qualified_param)));
750 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
751 bool visible = false;
754 if (track->marked_for_display()) {
759 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
760 _channel_command_menu_map[fully_qualified_param] = cmi;
761 cmi->set_active (visible);
763 /* one channel only */
770 /** Add a single menu item for a controller on one channel. */
772 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
774 const std::string& name)
776 using namespace Menu_Helpers;
778 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
779 for (uint8_t chn = 0; chn < 16; chn++) {
780 if (selected_channels & (0x0001 << chn)) {
782 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
783 ctl_items.push_back (
785 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
787 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
788 fully_qualified_param)));
789 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
791 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
792 fully_qualified_param);
794 bool visible = false;
796 if (track->marked_for_display()) {
801 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
802 _controller_menu_map[fully_qualified_param] = cmi;
803 cmi->set_active (visible);
805 /* one channel only */
811 /** Add a submenu with 1 item per channel for a controller on many channels. */
813 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
815 const std::string& name)
817 using namespace Menu_Helpers;
819 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
821 Menu* chn_menu = manage (new Menu);
822 MenuList& chn_items (chn_menu->items());
824 /* add a couple of items to hide/show this controller on all channels */
826 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
827 chn_items.push_back (
828 MenuElem (_("Hide all channels"),
829 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
830 false, param_without_channel)));
831 chn_items.push_back (
832 MenuElem (_("Show all channels"),
833 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
834 true, param_without_channel)));
836 for (uint8_t chn = 0; chn < 16; chn++) {
837 if (selected_channels & (0x0001 << chn)) {
839 /* for each selected channel, add a menu item for this controller */
841 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
842 chn_items.push_back (
843 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
844 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
845 fully_qualified_param)));
847 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
848 fully_qualified_param);
849 bool visible = false;
852 if (track->marked_for_display()) {
857 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
858 _controller_menu_map[fully_qualified_param] = cmi;
859 cmi->set_active (visible);
863 /* add the per-channel menu to the list of controllers, with the name of the controller */
864 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
866 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
869 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
870 MidiTimeAxisView::get_device_mode()
872 using namespace MIDI::Name;
874 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
876 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
879 return device_names->custom_device_mode_by_name(
880 gui_property (X_("midnam-custom-device-mode")));
883 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
884 MidiTimeAxisView::get_device_names()
886 using namespace MIDI::Name;
888 const std::string model = gui_property (X_("midnam-model-name"));
890 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
891 .document_by_model(model);
893 return midnam->master_device_names(model);
895 return boost::shared_ptr<MasterDeviceNames>();
900 MidiTimeAxisView::build_controller_menu ()
902 using namespace Menu_Helpers;
904 if (controller_menu) {
905 /* it exists and has not been invalidated by a channel mode change */
909 controller_menu = new Menu; // explicitly managed by us
910 MenuList& items (controller_menu->items());
912 /* create several "top level" menu items for sets of controllers (16 at a
913 time), and populate each one with a submenu for each controller+channel
914 combination covering the currently selected channels for this track
917 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
919 /* count the number of selected channels because we will build a different menu
920 structure if there is more than 1 selected.
924 for (uint8_t chn = 0; chn < 16; chn++) {
925 if (selected_channels & (0x0001 << chn)) {
932 using namespace MIDI::Name;
933 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
935 if (device_names && !device_names->controls().empty()) {
936 /* Controllers names available in midnam file, generate fancy menu */
937 unsigned n_items = 0;
938 unsigned n_groups = 0;
940 /* TODO: This is not correct, should look up the currently applicable ControlNameList
941 and only build a menu for that one. */
942 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
943 l != device_names->controls().end(); ++l) {
944 boost::shared_ptr<ControlNameList> name_list = l->second;
945 Menu* ctl_menu = NULL;
947 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
948 c != name_list->controls().end();) {
949 const uint16_t ctl = c->second->number();
950 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
951 /* Skip bank select controllers since they're handled specially */
953 /* Create a new submenu */
954 ctl_menu = manage (new Menu);
957 MenuList& ctl_items (ctl_menu->items());
959 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
961 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
966 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
967 /* Submenu has 16 items or we're done, add it to controller menu and reset */
969 MenuElem(string_compose(_("Controllers %1-%2"),
970 (16 * n_groups), (16 * n_groups) + n_items - 1),
979 /* No controllers names, generate generic numeric menu */
980 for (int i = 0; i < 127; i += 16) {
981 Menu* ctl_menu = manage (new Menu);
982 MenuList& ctl_items (ctl_menu->items());
984 for (int ctl = i; ctl < i+16; ++ctl) {
985 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
986 /* Skip bank select controllers since they're handled specially */
991 add_multi_channel_controller_item(
992 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
994 add_single_channel_controller_item(
995 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
999 /* Add submenu for this block of controllers to controller menu */
1001 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1008 MidiTimeAxisView::build_note_mode_menu()
1010 using namespace Menu_Helpers;
1012 Menu* mode_menu = manage (new Menu);
1013 MenuList& items = mode_menu->items();
1014 mode_menu->set_name ("ArdourContextMenu");
1016 RadioMenuItem::Group mode_group;
1018 RadioMenuElem (mode_group,_("Sustained"),
1019 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1021 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1022 _note_mode_item->set_active(_note_mode == Sustained);
1025 RadioMenuElem (mode_group, _("Percussive"),
1026 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1027 Percussive, true)));
1028 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1029 _percussion_mode_item->set_active(_note_mode == Percussive);
1035 MidiTimeAxisView::build_color_mode_menu()
1037 using namespace Menu_Helpers;
1039 Menu* mode_menu = manage (new Menu);
1040 MenuList& items = mode_menu->items();
1041 mode_menu->set_name ("ArdourContextMenu");
1043 RadioMenuItem::Group mode_group;
1045 RadioMenuElem (mode_group, _("Meter Colors"),
1046 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1047 MeterColors, false, true, true)));
1048 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1049 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1052 RadioMenuElem (mode_group, _("Channel Colors"),
1053 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1054 ChannelColors, false, true, true)));
1055 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1056 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1059 RadioMenuElem (mode_group, _("Track Color"),
1060 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1061 TrackColor, false, true, true)));
1062 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1063 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1069 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1071 if (apply_to_selection) {
1072 _editor.get_selection().tracks.foreach_midi_time_axis (
1073 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1075 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1077 midi_track()->set_note_mode(mode);
1078 set_gui_property ("note-mode", enum_2_string(_note_mode));
1079 _view->redisplay_track();
1085 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1087 if (apply_to_selection) {
1088 _editor.get_selection().tracks.foreach_midi_time_axis (
1089 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1091 if (_color_mode == mode && !force) {
1095 if (_channel_selector) {
1096 if (mode == ChannelColors) {
1097 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1099 _channel_selector->set_default_channel_color();
1104 set_gui_property ("color-mode", enum_2_string(_color_mode));
1106 _view->redisplay_track();
1112 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1114 if (apply_to_selection) {
1115 _editor.get_selection().tracks.foreach_midi_time_axis (
1116 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1118 if (!_ignore_signals) {
1119 midi_view()->set_note_range(range);
1125 MidiTimeAxisView::update_range()
1130 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1132 using namespace MIDI::Name;
1134 if (apply_to_selection) {
1135 _editor.get_selection().tracks.foreach_midi_time_axis (
1136 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1139 // Show existing automation
1140 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1142 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1143 create_automation_child(*i, true);
1146 // Show automation for all controllers named in midnam file
1147 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1148 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1149 device_names && !device_names->controls().empty()) {
1150 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1151 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1152 for (uint32_t chn = 0; chn < 16; ++chn) {
1153 if ((selected_channels & (0x0001 << chn)) == 0) {
1154 // Channel not in use
1158 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1164 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1165 chan_names->control_list_name());
1166 if (!control_names) {
1170 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1171 c != control_names->controls().end();
1173 const uint16_t ctl = c->second->number();
1174 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1175 /* Skip bank select controllers since they're handled specially */
1176 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1177 create_automation_child(param, true);
1184 RouteTimeAxisView::show_all_automation ();
1189 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1191 if (apply_to_selection) {
1192 _editor.get_selection().tracks.foreach_midi_time_axis (
1193 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1196 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1198 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1199 create_automation_child (*i, true);
1203 RouteTimeAxisView::show_existing_automation ();
1207 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1210 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1212 if (param.type() == NullAutomation) {
1216 AutomationTracks::iterator existing = _automation_tracks.find (param);
1218 if (existing != _automation_tracks.end()) {
1220 /* automation track created because we had existing data for
1221 * the processor, but visibility may need to be controlled
1222 * since it will have been set visible by default.
1225 existing->second->set_marked_for_display (show);
1234 boost::shared_ptr<AutomationTimeAxisView> track;
1235 boost::shared_ptr<AutomationControl> control;
1238 switch (param.type()) {
1240 case GainAutomation:
1241 create_gain_automation_child (param, show);
1244 case MuteAutomation:
1245 create_mute_automation_child (param, show);
1248 case PluginAutomation:
1249 /* handled elsewhere */
1252 case MidiCCAutomation:
1253 case MidiPgmChangeAutomation:
1254 case MidiPitchBenderAutomation:
1255 case MidiChannelPressureAutomation:
1256 case MidiSystemExclusiveAutomation:
1257 /* These controllers are region "automation" - they are owned
1258 * by regions (and their MidiModels), not by the track. As a
1259 * result there is no AutomationList/Line for the track, but we create
1260 * a controller for the user to write immediate events, so the editor
1261 * can act as a control surface for the present MIDI controllers.
1263 * TODO: Record manipulation of the controller to regions?
1266 control = _route->automation_control(param, true);
1267 track.reset (new AutomationTimeAxisView (
1270 control ? _route : boost::shared_ptr<Automatable> (),
1277 _route->describe_parameter(param)));
1280 _view->foreach_regionview (
1281 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1284 add_automation_child (param, track, show);
1286 reshow_selection (_editor.get_selection().time);
1291 case PanWidthAutomation:
1292 case PanElevationAutomation:
1293 case PanAzimuthAutomation:
1294 ensure_pan_views (show);
1298 error << "MidiTimeAxisView: unknown automation child "
1299 << EventTypeMap::instance().to_symbol(param) << endmsg;
1304 MidiTimeAxisView::route_active_changed ()
1306 RouteUI::route_active_changed ();
1307 update_control_names();
1311 MidiTimeAxisView::update_control_names ()
1314 if (_route->active()) {
1315 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1316 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1318 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1319 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1321 } else { // MIDI bus (which doesn't exist yet..)
1322 if (_route->active()) {
1323 controls_base_selected_name = "BusControlsBaseSelected";
1324 controls_base_unselected_name = "BusControlsBaseUnselected";
1326 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1327 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1332 controls_ebox.set_name (controls_base_selected_name);
1333 time_axis_frame.set_name (controls_base_selected_name);
1335 controls_ebox.set_name (controls_base_unselected_name);
1336 time_axis_frame.set_name (controls_base_unselected_name);
1341 MidiTimeAxisView::set_note_selection (uint8_t note)
1343 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1345 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1347 if (_view->num_selected_regionviews() == 0) {
1348 _view->foreach_regionview (
1349 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1352 _view->foreach_selected_regionview (
1353 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1357 _editor.commit_reversible_selection_op();
1361 MidiTimeAxisView::add_note_selection (uint8_t note)
1363 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1365 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1367 if (_view->num_selected_regionviews() == 0) {
1368 _view->foreach_regionview (
1369 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1372 _view->foreach_selected_regionview (
1373 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1377 _editor.commit_reversible_selection_op();
1381 MidiTimeAxisView::extend_note_selection (uint8_t note)
1383 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1385 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1387 if (_view->num_selected_regionviews() == 0) {
1388 _view->foreach_regionview (
1389 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1392 _view->foreach_selected_regionview (
1393 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1397 _editor.commit_reversible_selection_op();
1401 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1403 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1405 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1407 if (_view->num_selected_regionviews() == 0) {
1408 _view->foreach_regionview (
1409 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1412 _view->foreach_selected_regionview (
1413 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1417 _editor.commit_reversible_selection_op();
1421 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > >& selection)
1423 _view->foreach_regionview (
1424 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1428 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1430 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1434 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1436 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1440 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1442 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1446 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1448 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1452 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection)
1454 Evoral::Sequence<Temporal::Beats>::Notes selected;
1455 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1457 std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > notes;
1459 Evoral::Sequence<Temporal::Beats>::Notes::iterator sel_it;
1460 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1461 notes.insert (*sel_it);
1464 if (!notes.empty()) {
1465 selection.push_back (make_pair ((rv)->region()->id(), notes));
1470 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1472 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1476 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1477 bool changed = false;
1481 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1483 for (uint32_t chn = 0; chn < 16; ++chn) {
1484 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1485 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1491 if ((selected_channels & (0x0001 << chn)) == 0) {
1492 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1493 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1495 changed = track->set_marked_for_display (false) || changed;
1497 changed = track->set_marked_for_display (true) || changed;
1504 /* TODO: Bender, Pressure */
1506 /* invalidate the controller menu, so that we rebuild it next time */
1507 _controller_menu_map.clear ();
1508 delete controller_menu;
1509 controller_menu = 0;
1517 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1519 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1524 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1525 if (i != _controller_menu_map.end()) {
1529 i = _channel_command_menu_map.find (param);
1530 if (i != _channel_command_menu_map.end()) {
1537 boost::shared_ptr<MidiRegion>
1538 MidiTimeAxisView::add_region (samplepos_t f, samplecnt_t length, bool commit)
1540 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1541 MusicSample pos (f, 0);
1544 real_editor->begin_reversible_command (Operations::create_region);
1546 playlist()->clear_changes ();
1548 real_editor->snap_to (pos, RoundNearest);
1550 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1553 plist.add (ARDOUR::Properties::start, 0);
1554 plist.add (ARDOUR::Properties::length, length);
1555 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1557 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1558 /* sets beat position */
1559 region->set_position (pos.sample, pos.division);
1560 playlist()->add_region (region, pos.sample, 1.0, false, pos.division);
1561 _session->add_command (new StatefulDiffCommand (playlist()));
1564 real_editor->commit_reversible_command ();
1567 return boost::dynamic_pointer_cast<MidiRegion>(region);
1571 MidiTimeAxisView::ensure_step_editor ()
1573 if (!_step_editor) {
1574 _step_editor = new StepEditor (_editor, midi_track(), *this);
1579 MidiTimeAxisView::start_step_editing ()
1581 ensure_step_editor ();
1582 _step_editor->start_step_editing ();
1586 MidiTimeAxisView::stop_step_editing ()
1589 _step_editor->stop_step_editing ();
1593 /** @return channel (counted from 0) to add an event to, based on the current setting
1594 * of the channel selector.
1597 MidiTimeAxisView::get_channel_for_add () const
1599 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1601 uint8_t channel = 0;
1603 /* pick the highest selected channel, unless all channels are selected,
1604 which is interpreted to mean channel 1 (zero)
1607 for (uint16_t i = 0; i < 16; ++i) {
1608 if (chn_mask & (1<<i)) {
1614 if (chn_cnt == 16) {
1622 MidiTimeAxisView::note_range_changed ()
1624 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1625 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1629 MidiTimeAxisView::contents_height_changed ()
1631 _range_scroomer->queue_resize ();
1635 MidiTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1637 if (!_editor.internal_editing()) {
1638 // Non-internal paste, paste regions like any other route
1639 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1642 return midi_view()->paste(pos, selection, ctx, sub_num);