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)
126 , _patch_change_dialog (0)
128 _midnam_model_selector.disable_scrolling();
129 _midnam_custom_device_mode_selector.disable_scrolling();
133 MidiTimeAxisView::set_note_highlight (uint8_t note) {
134 _piano_roll_header->set_note_highlight (note);
138 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
142 _view = new MidiStreamView (*this);
145 _piano_roll_header = new PianoRollHeader(*midi_view());
146 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
147 _range_scroomer->DoubleClicked.connect (
148 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
149 MidiStreamView::ContentsRange, false));
152 /* This next call will result in our height being set up, so it must come after
153 the creation of the piano roll / range scroomer as their visibility is set up
156 RouteTimeAxisView::set_route (rt);
158 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
160 subplugin_menu.set_name ("ArdourContextMenu");
162 if (!gui_property ("note-range-min").empty ()) {
163 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
164 atoi (gui_property ("note-range-max").c_str()),
168 _view->ContentsHeightChanged.connect (
169 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
171 ignore_toggle = false;
173 if (is_midi_track()) {
174 _note_mode = midi_track()->note_mode();
177 /* if set_state above didn't create a gain automation child, we need to make one */
178 if (automation_child (GainAutomation) == 0) {
179 create_automation_child (GainAutomation, false);
182 /* if set_state above didn't create a mute automation child, we need to make one */
183 if (automation_child (MuteAutomation) == 0) {
184 create_automation_child (MuteAutomation, false);
187 if (_route->panner_shell()) {
188 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
191 /* map current state of the route */
192 ensure_pan_views (false);
193 update_control_names();
194 processors_changed (RouteProcessorChange ());
196 _route->processors_changed.connect (*this, invalidator (*this),
197 boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
201 _piano_roll_header->SetNoteSelection.connect (
202 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
203 _piano_roll_header->AddNoteSelection.connect (
204 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
205 _piano_roll_header->ExtendNoteSelection.connect (
206 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
207 _piano_roll_header->ToggleNoteSelection.connect (
208 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
210 /* Update StreamView during scroomer drags.*/
212 _range_scroomer->DragStarting.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::start_scroomer_update));
214 _range_scroomer->DragFinishing.connect (
215 sigc::mem_fun (*this, &MidiTimeAxisView::stop_scroomer_update));
217 /* Put the scroomer and the keyboard in a VBox with a padding
218 label so that they can be reduced in height for stacked-view
222 HSeparator* separator = manage (new HSeparator());
223 separator->set_name("TrackSeparator");
224 separator->set_size_request(-1, 1);
227 VBox* v = manage (new VBox);
228 HBox* h = manage (new HBox);
229 h->pack_end (*_piano_roll_header);
230 h->pack_end (*_range_scroomer);
231 v->pack_start (*separator, false, false);
232 v->pack_start (*h, true, true);
235 top_hbox.remove(scroomer_placeholder);
236 time_axis_hbox.pack_end(*v, false, false, 0);
237 midi_scroomer_size_group->add_widget (*v);
239 midi_view()->NoteRangeChanged.connect (
240 sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
242 /* ask for notifications of any new RegionViews */
243 _view->RegionViewAdded.connect (
244 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
246 if (!_editor.have_idled()) {
247 /* first idle will do what we need */
253 if (gui_property (X_("midnam-model-name")).empty()) {
254 set_gui_property (X_("midnam-model-name"), "Generic");
257 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
258 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
260 set_gui_property (X_("midnam-custom-device-mode"),
261 *device_names->custom_device_mode_names().begin());
265 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
266 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
268 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
269 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
271 _midi_controls_box.set_homogeneous(false);
272 _midi_controls_box.set_border_width (2);
274 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
275 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
278 setup_midnam_patches ();
279 update_patch_selector ();
281 model_changed (gui_property(X_("midnam-model-name")));
282 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
284 controls_vbox.pack_start(_midi_controls_box, false, false);
286 const string color_mode = gui_property ("color-mode");
287 if (!color_mode.empty()) {
288 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
289 if (_channel_selector && _color_mode == ChannelColors) {
290 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
294 set_color_mode (_color_mode, true, false);
296 const string note_mode = gui_property ("note-mode");
297 if (!note_mode.empty()) {
298 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
299 if (_percussion_mode_item) {
300 _percussion_mode_item->set_active (_note_mode == Percussive);
304 /* Look for any GUI object state nodes that represent automation children
305 * that should exist, and create the children.
308 const list<string> gui_ids = gui_object_state().all_ids ();
309 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
312 Evoral::Parameter parameter (0, 0, 0);
314 bool const p = AutomationTimeAxisView::parse_state_id (
315 *i, route_id, has_parameter, parameter);
316 if (p && route_id == _route->id () && has_parameter) {
317 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
318 create_automation_child (parameter, string_to<bool> (visible));
324 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
326 RouteTimeAxisView::processors_changed (c);
327 update_patch_selector ();
331 MidiTimeAxisView::first_idle ()
338 MidiTimeAxisView::~MidiTimeAxisView ()
340 delete _channel_selector;
342 delete _piano_roll_header;
343 _piano_roll_header = 0;
345 delete _range_scroomer;
348 delete controller_menu;
351 delete _patch_change_dialog;
352 _patch_change_dialog = 0;
356 MidiTimeAxisView::check_step_edit ()
358 ensure_step_editor ();
359 _step_editor->check_step_edit ();
363 MidiTimeAxisView::setup_midnam_patches ()
365 typedef MIDI::Name::MidiPatchManager PatchManager;
366 PatchManager& patch_manager = PatchManager::instance();
368 _midnam_model_selector.clear_items ();
369 for (PatchManager::DeviceNamesByMaker::const_iterator m = patch_manager.devices_by_manufacturer().begin();
370 m != patch_manager.devices_by_manufacturer().end(); ++m) {
371 Menu* menu = Gtk::manage(new Menu);
372 Menu_Helpers::MenuList& items = menu->items();
374 // Build manufacturer submenu
375 for (MIDI::Name::MIDINameDocument::MasterDeviceNamesList::const_iterator n = m->second.begin();
376 n != m->second.end(); ++n) {
377 Menu_Helpers::MenuElem elem = Gtk::Menu_Helpers::MenuElem(
379 sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::model_changed),
382 items.push_back(elem);
385 // Add manufacturer submenu to selector
386 _midnam_model_selector.AddMenuElem(Menu_Helpers::MenuElem(m->first, *menu));
389 if (!get_device_names()) {
390 model_changed ("Generic");
395 MidiTimeAxisView::drop_instrument_ref ()
397 midnam_connection.drop_connections ();
400 MidiTimeAxisView::start_scroomer_update ()
402 _note_range_changed_connection.disconnect();
403 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
404 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
407 MidiTimeAxisView::stop_scroomer_update ()
409 _note_range_changed_connection.disconnect();
413 MidiTimeAxisView::update_patch_selector ()
415 typedef MIDI::Name::MidiPatchManager PatchManager;
416 PatchManager& patch_manager = PatchManager::instance();
418 bool pluginprovided = false;
420 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
421 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
422 if (pi && pi->plugin ()->has_midnam ()) {
423 midnam_connection.drop_connections ();
424 the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
425 boost::bind (&MidiTimeAxisView::drop_instrument_ref, this),
427 pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
428 boost::bind (&Plugin::read_midnam, pi->plugin ()),
431 pluginprovided = true;
432 std::string model_name = pi->plugin ()->midnam_model ();
433 if (gui_property (X_("midnam-model-name")) != model_name) {
434 model_changed (model_name);
439 if (patch_manager.all_models().empty() || pluginprovided) {
440 _midnam_model_selector.hide ();
441 _midnam_custom_device_mode_selector.hide ();
443 _midnam_model_selector.show ();
444 _midnam_custom_device_mode_selector.show ();
449 MidiTimeAxisView::model_changed(const std::string& model)
451 set_gui_property (X_("midnam-model-name"), model);
453 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
454 .custom_device_mode_names_by_model(model);
456 _midnam_model_selector.set_text(model);
457 _midnam_custom_device_mode_selector.clear_items();
459 for (std::list<std::string>::const_iterator i = device_modes.begin();
460 i != device_modes.end(); ++i) {
461 _midnam_custom_device_mode_selector.AddMenuElem(
462 Gtk::Menu_Helpers::MenuElem(
463 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
467 if (!device_modes.empty()) {
468 custom_device_mode_changed(device_modes.front());
471 if (device_modes.size() > 1) {
472 _midnam_custom_device_mode_selector.show();
474 _midnam_custom_device_mode_selector.hide();
477 // now this is a real bad hack
478 if (device_modes.size() > 0) {
479 _route->instrument_info().set_external_instrument (model, device_modes.front());
481 _route->instrument_info().set_external_instrument (model, "");
484 // Rebuild controller menu
485 _controller_menu_map.clear ();
486 delete controller_menu;
488 build_automation_action_menu(false);
492 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
494 const std::string model = gui_property (X_("midnam-model-name"));
496 set_gui_property (X_("midnam-custom-device-mode"), mode);
497 _midnam_custom_device_mode_selector.set_text(mode);
498 _route->instrument_info().set_external_instrument (model, mode);
502 MidiTimeAxisView::midi_view()
504 return dynamic_cast<MidiStreamView*>(_view);
508 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
510 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
511 _midi_controls_box.show ();
513 _midi_controls_box.hide();
516 if (h >= KEYBOARD_MIN_HEIGHT) {
517 if (is_track() && _range_scroomer) {
518 _range_scroomer->show();
520 if (is_track() && _piano_roll_header) {
521 _piano_roll_header->show();
524 if (is_track() && _range_scroomer) {
525 _range_scroomer->hide();
527 if (is_track() && _piano_roll_header) {
528 _piano_roll_header->hide();
532 /* We need to do this after changing visibility of our stuff, as it will
533 eventually trigger a call to Editor::reset_controls_layout_width(),
534 which needs to know if we have just shown or hidden a scroomer /
537 RouteTimeAxisView::set_height (h, m);
541 MidiTimeAxisView::append_extra_display_menu_items ()
543 using namespace Menu_Helpers;
545 MenuList& items = display_menu->items();
548 Menu *range_menu = manage(new Menu);
549 MenuList& range_items = range_menu->items();
550 range_menu->set_name ("ArdourContextMenu");
552 range_items.push_back (
553 MenuElem (_("Show Full Range"),
554 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
555 MidiStreamView::FullRange, true)));
557 range_items.push_back (
558 MenuElem (_("Fit Contents"),
559 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
560 MidiStreamView::ContentsRange, true)));
562 items.push_back (MenuElem (_("Note Range"), *range_menu));
563 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
564 items.push_back (MenuElem (_("Channel Selector"),
565 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
567 items.push_back (MenuElem (_("Select Patch..."),
568 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
570 color_mode_menu = build_color_mode_menu();
571 if (color_mode_menu) {
572 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
575 items.push_back (SeparatorElem ());
579 MidiTimeAxisView::toggle_channel_selector ()
581 if (!_channel_selector) {
582 _channel_selector = new MidiChannelSelectorWindow (midi_track());
584 if (_color_mode == ChannelColors) {
585 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
587 _channel_selector->set_default_channel_color ();
590 _channel_selector->show_all ();
592 _channel_selector->cycle_visibility ();
597 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
599 using namespace Menu_Helpers;
601 /* If we have a controller menu, we need to detach it before
602 RouteTimeAxis::build_automation_action_menu destroys the
603 menu it is attached to. Otherwise GTK destroys
604 controller_menu's gobj, meaning that it can't be reattached
605 below. See bug #3134.
608 if (controller_menu) {
609 detach_menu (*controller_menu);
612 _channel_command_menu_map.clear ();
613 RouteTimeAxisView::build_automation_action_menu (for_selection);
615 MenuList& automation_items = automation_action_menu->items();
617 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
619 if (selected_channels != 0) {
621 automation_items.push_back (SeparatorElem());
623 /* these 2 MIDI "command" types are semantically more like automation
624 than note data, but they are not MIDI controllers. We give them
625 special status in this menu, since they will not show up in the
626 controller list and anyone who actually knows something about MIDI
627 (!) would not expect to find them there.
630 add_channel_command_menu_item (
631 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
632 automation_items.back().set_sensitive (
633 !for_selection || _editor.get_selection().tracks.size() == 1);
634 add_channel_command_menu_item (
635 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
636 automation_items.back().set_sensitive (
637 !for_selection || _editor.get_selection().tracks.size() == 1);
639 /* now all MIDI controllers. Always offer the possibility that we will
640 rebuild the controllers menu since it might need to be updated after
641 a channel mode change or other change. Also detach it first in case
642 it has been used anywhere else.
645 build_controller_menu ();
647 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
649 if (!poly_pressure_menu) {
650 poly_pressure_menu = new Gtk::Menu;
653 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
655 automation_items.back().set_sensitive (
656 !for_selection || _editor.get_selection().tracks.size() == 1);
658 automation_items.push_back (
659 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
660 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
665 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
667 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
669 for (uint8_t chn = 0; chn < 16; chn++) {
670 if (selected_channels & (0x0001 << chn)) {
672 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
673 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
676 menu->set_active (yn);
683 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
685 AutomationType auto_type,
688 using namespace Menu_Helpers;
690 /* count the number of selected channels because we will build a different menu
691 structure if there is more than 1 selected.
694 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
697 for (uint8_t chn = 0; chn < 16; chn++) {
698 if (selected_channels & (0x0001 << chn)) {
707 /* multiple channels - create a submenu, with 1 item per channel */
709 Menu* chn_menu = manage (new Menu);
710 MenuList& chn_items (chn_menu->items());
711 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
713 /* add a couple of items to hide/show all of them */
715 chn_items.push_back (
716 MenuElem (_("Hide all channels"),
717 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
718 false, param_without_channel)));
719 chn_items.push_back (
720 MenuElem (_("Show all channels"),
721 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
722 true, param_without_channel)));
724 for (uint8_t chn = 0; chn < 16; chn++) {
725 if (selected_channels & (0x0001 << chn)) {
727 /* for each selected channel, add a menu item for this controller */
729 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
730 chn_items.push_back (
731 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
732 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
733 fully_qualified_param)));
735 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
736 bool visible = false;
739 if (track->marked_for_display()) {
744 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
745 _channel_command_menu_map[fully_qualified_param] = cmi;
746 cmi->set_active (visible);
750 /* now create an item in the parent menu that has the per-channel list as a submenu */
752 items.push_back (MenuElem (label, *chn_menu));
756 /* just one channel - create a single menu item for this command+channel combination*/
758 for (uint8_t chn = 0; chn < 16; chn++) {
759 if (selected_channels & (0x0001 << chn)) {
761 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
763 CheckMenuElem (label,
764 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
765 fully_qualified_param)));
767 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
768 bool visible = false;
771 if (track->marked_for_display()) {
776 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
777 _channel_command_menu_map[fully_qualified_param] = cmi;
778 cmi->set_active (visible);
780 /* one channel only */
787 /** Add a single menu item for a controller on one channel. */
789 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
791 const std::string& name)
793 using namespace Menu_Helpers;
795 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
796 for (uint8_t chn = 0; chn < 16; chn++) {
797 if (selected_channels & (0x0001 << chn)) {
799 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
800 ctl_items.push_back (
802 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
804 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
805 fully_qualified_param)));
806 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
808 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
809 fully_qualified_param);
811 bool visible = false;
813 if (track->marked_for_display()) {
818 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
819 _controller_menu_map[fully_qualified_param] = cmi;
820 cmi->set_active (visible);
822 /* one channel only */
828 /** Add a submenu with 1 item per channel for a controller on many channels. */
830 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
832 const std::string& name)
834 using namespace Menu_Helpers;
836 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
838 Menu* chn_menu = manage (new Menu);
839 MenuList& chn_items (chn_menu->items());
841 /* add a couple of items to hide/show this controller on all channels */
843 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
844 chn_items.push_back (
845 MenuElem (_("Hide all channels"),
846 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
847 false, param_without_channel)));
848 chn_items.push_back (
849 MenuElem (_("Show all channels"),
850 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
851 true, param_without_channel)));
853 for (uint8_t chn = 0; chn < 16; chn++) {
854 if (selected_channels & (0x0001 << chn)) {
856 /* for each selected channel, add a menu item for this controller */
858 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
859 chn_items.push_back (
860 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
861 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
862 fully_qualified_param)));
864 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
865 fully_qualified_param);
866 bool visible = false;
869 if (track->marked_for_display()) {
874 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
875 _controller_menu_map[fully_qualified_param] = cmi;
876 cmi->set_active (visible);
880 /* add the per-channel menu to the list of controllers, with the name of the controller */
881 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
883 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
886 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
887 MidiTimeAxisView::get_device_mode()
889 using namespace MIDI::Name;
891 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
893 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
896 return device_names->custom_device_mode_by_name(
897 gui_property (X_("midnam-custom-device-mode")));
900 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
901 MidiTimeAxisView::get_device_names()
903 using namespace MIDI::Name;
905 const std::string model = gui_property (X_("midnam-model-name"));
907 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
908 .document_by_model(model);
910 return midnam->master_device_names(model);
912 return boost::shared_ptr<MasterDeviceNames>();
917 MidiTimeAxisView::build_controller_menu ()
919 using namespace Menu_Helpers;
921 if (controller_menu) {
922 /* it exists and has not been invalidated by a channel mode change */
926 controller_menu = new Menu; // explicitly managed by us
927 MenuList& items (controller_menu->items());
929 /* create several "top level" menu items for sets of controllers (16 at a
930 time), and populate each one with a submenu for each controller+channel
931 combination covering the currently selected channels for this track
934 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
936 /* count the number of selected channels because we will build a different menu
937 structure if there is more than 1 selected.
941 for (uint8_t chn = 0; chn < 16; chn++) {
942 if (selected_channels & (0x0001 << chn)) {
949 using namespace MIDI::Name;
950 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
952 if (device_names && !device_names->controls().empty()) {
953 /* Controllers names available in midnam file, generate fancy menu */
954 unsigned n_items = 0;
955 unsigned n_groups = 0;
957 /* TODO: This is not correct, should look up the currently applicable ControlNameList
958 and only build a menu for that one. */
959 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
960 l != device_names->controls().end(); ++l) {
961 boost::shared_ptr<ControlNameList> name_list = l->second;
962 Menu* ctl_menu = NULL;
964 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
965 c != name_list->controls().end();) {
966 const uint16_t ctl = c->second->number();
967 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
968 /* Skip bank select controllers since they're handled specially */
970 /* Create a new submenu */
971 ctl_menu = manage (new Menu);
974 MenuList& ctl_items (ctl_menu->items());
976 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
978 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
983 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
984 /* Submenu has 16 items or we're done, add it to controller menu and reset */
986 MenuElem(string_compose(_("Controllers %1-%2"),
987 (16 * n_groups), (16 * n_groups) + n_items - 1),
996 /* No controllers names, generate generic numeric menu */
997 for (int i = 0; i < 127; i += 16) {
998 Menu* ctl_menu = manage (new Menu);
999 MenuList& ctl_items (ctl_menu->items());
1001 for (int ctl = i; ctl < i+16; ++ctl) {
1002 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1003 /* Skip bank select controllers since they're handled specially */
1008 add_multi_channel_controller_item(
1009 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1011 add_single_channel_controller_item(
1012 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1016 /* Add submenu for this block of controllers to controller menu */
1018 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1025 MidiTimeAxisView::build_note_mode_menu()
1027 using namespace Menu_Helpers;
1029 Menu* mode_menu = manage (new Menu);
1030 MenuList& items = mode_menu->items();
1031 mode_menu->set_name ("ArdourContextMenu");
1033 RadioMenuItem::Group mode_group;
1035 RadioMenuElem (mode_group,_("Sustained"),
1036 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1038 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1039 _note_mode_item->set_active(_note_mode == Sustained);
1042 RadioMenuElem (mode_group, _("Percussive"),
1043 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1044 Percussive, true)));
1045 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1046 _percussion_mode_item->set_active(_note_mode == Percussive);
1052 MidiTimeAxisView::build_color_mode_menu()
1054 using namespace Menu_Helpers;
1056 Menu* mode_menu = manage (new Menu);
1057 MenuList& items = mode_menu->items();
1058 mode_menu->set_name ("ArdourContextMenu");
1060 RadioMenuItem::Group mode_group;
1062 RadioMenuElem (mode_group, _("Meter Colors"),
1063 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1064 MeterColors, false, true, true)));
1065 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1066 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1069 RadioMenuElem (mode_group, _("Channel Colors"),
1070 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1071 ChannelColors, false, true, true)));
1072 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1073 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1076 RadioMenuElem (mode_group, _("Track Color"),
1077 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1078 TrackColor, false, true, true)));
1079 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1080 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1086 MidiTimeAxisView::send_patch_change ()
1091 if (_patch_change_dialog) {
1092 _patch_change_dialog->present ();
1096 PatchChangeGridDialog* d = new PatchChangeGridDialog (string_compose (_("Select Patch for '%1'"), _route->name ()), _route);
1097 _patch_change_dialog = d;
1102 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1104 if (apply_to_selection) {
1105 _editor.get_selection().tracks.foreach_midi_time_axis (
1106 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1108 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1110 midi_track()->set_note_mode(mode);
1111 set_gui_property ("note-mode", enum_2_string(_note_mode));
1112 _view->redisplay_track();
1118 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1120 if (apply_to_selection) {
1121 _editor.get_selection().tracks.foreach_midi_time_axis (
1122 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1124 if (_color_mode == mode && !force) {
1128 if (_channel_selector) {
1129 if (mode == ChannelColors) {
1130 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1132 _channel_selector->set_default_channel_color();
1137 set_gui_property ("color-mode", enum_2_string(_color_mode));
1139 _view->redisplay_track();
1145 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1147 if (apply_to_selection) {
1148 _editor.get_selection().tracks.foreach_midi_time_axis (
1149 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1151 if (!_ignore_signals) {
1152 midi_view()->set_note_range(range);
1158 MidiTimeAxisView::update_range()
1163 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1165 using namespace MIDI::Name;
1167 if (apply_to_selection) {
1168 _editor.get_selection().tracks.foreach_midi_time_axis (
1169 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1172 // Show existing automation
1173 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1175 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1176 create_automation_child(*i, true);
1179 // Show automation for all controllers named in midnam file
1180 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1181 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1182 device_names && !device_names->controls().empty()) {
1183 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1184 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1185 for (uint32_t chn = 0; chn < 16; ++chn) {
1186 if ((selected_channels & (0x0001 << chn)) == 0) {
1187 // Channel not in use
1191 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1197 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1198 chan_names->control_list_name());
1199 if (!control_names) {
1203 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1204 c != control_names->controls().end();
1206 const uint16_t ctl = c->second->number();
1207 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1208 /* Skip bank select controllers since they're handled specially */
1209 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1210 create_automation_child(param, true);
1217 RouteTimeAxisView::show_all_automation ();
1222 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1224 if (apply_to_selection) {
1225 _editor.get_selection().tracks.foreach_midi_time_axis (
1226 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1229 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1231 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1232 create_automation_child (*i, true);
1236 RouteTimeAxisView::show_existing_automation ();
1240 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1243 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1245 if (param.type() == NullAutomation) {
1249 AutomationTracks::iterator existing = _automation_tracks.find (param);
1251 if (existing != _automation_tracks.end()) {
1253 /* automation track created because we had existing data for
1254 * the processor, but visibility may need to be controlled
1255 * since it will have been set visible by default.
1258 existing->second->set_marked_for_display (show);
1267 boost::shared_ptr<AutomationTimeAxisView> track;
1268 boost::shared_ptr<AutomationControl> control;
1271 switch (param.type()) {
1273 case GainAutomation:
1274 create_gain_automation_child (param, show);
1277 case MuteAutomation:
1278 create_mute_automation_child (param, show);
1281 case PluginAutomation:
1282 /* handled elsewhere */
1285 case MidiCCAutomation:
1286 case MidiPgmChangeAutomation:
1287 case MidiPitchBenderAutomation:
1288 case MidiChannelPressureAutomation:
1289 case MidiSystemExclusiveAutomation:
1290 /* These controllers are region "automation" - they are owned
1291 * by regions (and their MidiModels), not by the track. As a
1292 * result there is no AutomationList/Line for the track, but we create
1293 * a controller for the user to write immediate events, so the editor
1294 * can act as a control surface for the present MIDI controllers.
1296 * TODO: Record manipulation of the controller to regions?
1299 control = _route->automation_control(param, true);
1300 track.reset (new AutomationTimeAxisView (
1303 control ? _route : boost::shared_ptr<Automatable> (),
1310 _route->describe_parameter(param)));
1313 _view->foreach_regionview (
1314 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1317 add_automation_child (param, track, show);
1319 reshow_selection (_editor.get_selection().time);
1324 case PanWidthAutomation:
1325 case PanElevationAutomation:
1326 case PanAzimuthAutomation:
1327 ensure_pan_views (show);
1331 error << "MidiTimeAxisView: unknown automation child "
1332 << EventTypeMap::instance().to_symbol(param) << endmsg;
1337 MidiTimeAxisView::route_active_changed ()
1339 RouteUI::route_active_changed ();
1340 update_control_names();
1344 MidiTimeAxisView::update_control_names ()
1347 if (_route->active()) {
1348 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1349 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1351 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1352 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1354 } else { // MIDI bus (which doesn't exist yet..)
1355 if (_route->active()) {
1356 controls_base_selected_name = "BusControlsBaseSelected";
1357 controls_base_unselected_name = "BusControlsBaseUnselected";
1359 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1360 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1365 controls_ebox.set_name (controls_base_selected_name);
1366 time_axis_frame.set_name (controls_base_selected_name);
1368 controls_ebox.set_name (controls_base_unselected_name);
1369 time_axis_frame.set_name (controls_base_unselected_name);
1374 MidiTimeAxisView::set_note_selection (uint8_t note)
1376 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1378 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1380 if (_view->num_selected_regionviews() == 0) {
1381 _view->foreach_regionview (
1382 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1385 _view->foreach_selected_regionview (
1386 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1390 _editor.commit_reversible_selection_op();
1394 MidiTimeAxisView::add_note_selection (uint8_t note)
1396 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1398 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1400 if (_view->num_selected_regionviews() == 0) {
1401 _view->foreach_regionview (
1402 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1405 _view->foreach_selected_regionview (
1406 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1410 _editor.commit_reversible_selection_op();
1414 MidiTimeAxisView::extend_note_selection (uint8_t note)
1416 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1418 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1420 if (_view->num_selected_regionviews() == 0) {
1421 _view->foreach_regionview (
1422 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1425 _view->foreach_selected_regionview (
1426 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1430 _editor.commit_reversible_selection_op();
1434 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1436 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1438 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1440 if (_view->num_selected_regionviews() == 0) {
1441 _view->foreach_regionview (
1442 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1445 _view->foreach_selected_regionview (
1446 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1450 _editor.commit_reversible_selection_op();
1454 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1456 _view->foreach_regionview (
1457 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1461 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1463 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1467 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1469 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1473 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1475 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1479 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1481 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1485 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1487 Evoral::Sequence<Evoral::Beats>::Notes selected;
1488 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1490 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1492 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1493 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1494 notes.insert (*sel_it);
1497 if (!notes.empty()) {
1498 selection.push_back (make_pair ((rv)->region()->id(), notes));
1503 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1505 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1509 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1510 bool changed = false;
1514 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1516 for (uint32_t chn = 0; chn < 16; ++chn) {
1517 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1518 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1524 if ((selected_channels & (0x0001 << chn)) == 0) {
1525 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1526 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1528 changed = track->set_marked_for_display (false) || changed;
1530 changed = track->set_marked_for_display (true) || changed;
1537 /* TODO: Bender, Pressure */
1539 /* invalidate the controller menu, so that we rebuild it next time */
1540 _controller_menu_map.clear ();
1541 delete controller_menu;
1542 controller_menu = 0;
1550 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1552 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1557 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1558 if (i != _controller_menu_map.end()) {
1562 i = _channel_command_menu_map.find (param);
1563 if (i != _channel_command_menu_map.end()) {
1570 boost::shared_ptr<MidiRegion>
1571 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1573 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1574 MusicFrame pos (f, 0);
1577 real_editor->begin_reversible_command (Operations::create_region);
1579 playlist()->clear_changes ();
1581 real_editor->snap_to (pos, RoundNearest);
1583 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1586 plist.add (ARDOUR::Properties::start, 0);
1587 plist.add (ARDOUR::Properties::length, length);
1588 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1590 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1591 /* sets beat position */
1592 region->set_position (pos.frame, pos.division);
1593 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1594 _session->add_command (new StatefulDiffCommand (playlist()));
1597 real_editor->commit_reversible_command ();
1600 return boost::dynamic_pointer_cast<MidiRegion>(region);
1604 MidiTimeAxisView::ensure_step_editor ()
1606 if (!_step_editor) {
1607 _step_editor = new StepEditor (_editor, midi_track(), *this);
1612 MidiTimeAxisView::start_step_editing ()
1614 ensure_step_editor ();
1615 _step_editor->start_step_editing ();
1619 MidiTimeAxisView::stop_step_editing ()
1622 _step_editor->stop_step_editing ();
1626 /** @return channel (counted from 0) to add an event to, based on the current setting
1627 * of the channel selector.
1630 MidiTimeAxisView::get_channel_for_add () const
1632 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1634 uint8_t channel = 0;
1636 /* pick the highest selected channel, unless all channels are selected,
1637 which is interpreted to mean channel 1 (zero)
1640 for (uint16_t i = 0; i < 16; ++i) {
1641 if (chn_mask & (1<<i)) {
1647 if (chn_cnt == 16) {
1655 MidiTimeAxisView::note_range_changed ()
1657 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1658 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1662 MidiTimeAxisView::contents_height_changed ()
1664 _range_scroomer->queue_resize ();
1668 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1670 if (!_editor.internal_editing()) {
1671 // Non-internal paste, paste regions like any other route
1672 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1675 return midi_view()->paste(pos, selection, ctx, sub_num);