2 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
3 * Copyright (C) 2008-2012 Hans Baier <hansfbaier@googlemail.com>
4 * Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
7 * Copyright (C) 2013-2016 Tim Mayberry <mojofunk@gmail.com>
8 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2014-2017 Ben Loftis <ben@harrisonconsoles.com>
10 * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include <sigc++/bind.h>
36 #include <gtkmm/separator.h>
37 #include <gtkmm/stock.h>
39 #include "pbd/error.h"
41 #include "pbd/stl_delete.h"
42 #include "pbd/whitespace.h"
43 #include "pbd/basename.h"
44 #include "pbd/enumwriter.h"
45 #include "pbd/memento_command.h"
46 #include "pbd/stateful_diff_command.h"
48 #include "gtkmm2ext/gtk_ui.h"
49 #include "gtkmm2ext/utils.h"
51 #include "widgets/tooltips.h"
53 #include "ardour/event_type_map.h"
54 #include "ardour/midi_patch_manager.h"
55 #include "ardour/midi_playlist.h"
56 #include "ardour/midi_region.h"
57 #include "ardour/midi_source.h"
58 #include "ardour/midi_track.h"
59 #include "ardour/operations.h"
60 #include "ardour/pannable.h"
61 #include "ardour/panner.h"
62 #include "ardour/panner_shell.h"
63 #include "ardour/playlist.h"
64 #include "ardour/plugin_insert.h"
65 #include "ardour/profile.h"
66 #include "ardour/region.h"
67 #include "ardour/region_factory.h"
68 #include "ardour/route.h"
69 #include "ardour/session.h"
70 #include "ardour/session_object.h"
71 #include "ardour/source.h"
72 #include "ardour/track.h"
73 #include "ardour/types.h"
75 #include "automation_line.h"
76 #include "automation_time_axis.h"
79 #include "ghostregion.h"
80 #include "gui_thread.h"
82 #include "midi_channel_selector.h"
83 #include "midi_scroomer.h"
84 #include "midi_streamview.h"
85 #include "midi_region_view.h"
86 #include "midi_time_axis.h"
87 #include "patch_change_dialog.h"
88 #include "patch_change_widget.h"
89 #include "piano_roll_header.h"
90 #include "playlist_selector.h"
91 #include "plugin_selector.h"
92 #include "plugin_ui.h"
93 #include "point_selection.h"
94 #include "region_view.h"
95 #include "rgb_macros.h"
96 #include "selection.h"
97 #include "step_editor.h"
99 #include "note_base.h"
101 #include "ardour/midi_track.h"
103 #include "pbd/i18n.h"
105 using namespace ARDOUR;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
112 // Minimum height at which a control is displayed
113 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 160;
114 static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
116 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
117 : SessionHandlePtr (sess)
118 , RouteTimeAxisView (ed, sess, canvas)
119 , _ignore_signals(false)
121 , _piano_roll_header(0)
122 , _note_mode(Sustained)
124 , _percussion_mode_item(0)
125 , _color_mode(MeterColors)
126 , _meter_color_mode_item(0)
127 , _channel_color_mode_item(0)
128 , _track_color_mode_item(0)
129 , _channel_selector (0)
130 , _step_edit_item (0)
131 , controller_menu (0)
132 , poly_pressure_menu (0)
135 _midnam_model_selector.disable_scrolling();
136 _midnam_custom_device_mode_selector.disable_scrolling();
140 MidiTimeAxisView::set_note_highlight (uint8_t note) {
141 _piano_roll_header->set_note_highlight (note);
145 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
149 _view = new MidiStreamView (*this);
152 _piano_roll_header = new PianoRollHeader(*midi_view());
153 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
154 _range_scroomer->DoubleClicked.connect (
155 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
156 MidiStreamView::ContentsRange, false));
159 /* This next call will result in our height being set up, so it must come after
160 the creation of the piano roll / range scroomer as their visibility is set up
163 RouteTimeAxisView::set_route (rt);
165 _view->apply_color (ARDOUR_UI_UTILS::gdk_color_to_rgba (color()), StreamView::RegionColor);
167 subplugin_menu.set_name ("ArdourContextMenu");
169 _note_range_changed_connection.disconnect();
171 if (!gui_property ("note-range-min").empty ()) {
172 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
173 atoi (gui_property ("note-range-max").c_str()),
177 _view->ContentsHeightChanged.connect (
178 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
180 ignore_toggle = false;
182 if (is_midi_track()) {
183 _note_mode = midi_track()->note_mode();
186 /* if set_state above didn't create a gain automation child, we need to make one */
187 if (automation_child (GainAutomation) == 0) {
188 create_automation_child (GainAutomation, false);
191 /* if set_state above didn't create a mute automation child, we need to make one */
192 if (automation_child (MuteAutomation) == 0) {
193 create_automation_child (MuteAutomation, false);
196 if (_route->panner_shell()) {
197 _route->panner_shell()->Changed.connect (*this, invalidator (*this), boost::bind (&MidiTimeAxisView::ensure_pan_views, this, false), gui_context());
200 /* map current state of the route */
201 ensure_pan_views (false);
202 update_control_names();
203 processors_changed (RouteProcessorChange ());
206 _piano_roll_header->SetNoteSelection.connect (
207 sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
208 _piano_roll_header->AddNoteSelection.connect (
209 sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
210 _piano_roll_header->ExtendNoteSelection.connect (
211 sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
212 _piano_roll_header->ToggleNoteSelection.connect (
213 sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
215 /* Put the scroomer and the keyboard in a VBox with a padding
216 label so that they can be reduced in height for stacked-view
220 HSeparator* separator = manage (new HSeparator());
221 separator->set_name("TrackSeparator");
222 separator->set_size_request(-1, 1);
225 VBox* v = manage (new VBox);
226 HBox* h = manage (new HBox);
227 h->pack_end (*_piano_roll_header);
228 h->pack_end (*_range_scroomer);
229 v->pack_start (*separator, false, false);
230 v->pack_start (*h, true, true);
233 top_hbox.remove(scroomer_placeholder);
234 time_axis_hbox.pack_end(*v, false, false, 0);
235 midi_scroomer_size_group->add_widget (*v);
237 /* callback from StreamView scroomer drags, as well as
238 * automatic changes of note-range (e.g. at rec-stop).
239 * This callback is used to save the note-range-min/max
240 * GUI Object property
242 _note_range_changed_connection = midi_view()->NoteRangeChanged.connect (
243 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
245 /* ask for notifications of any new RegionViews */
246 _view->RegionViewAdded.connect (
247 sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
249 if (!_editor.have_idled()) {
250 /* first idle will do what we need */
256 if (gui_property (X_("midnam-model-name")).empty()) {
257 set_gui_property (X_("midnam-model-name"), "Generic");
260 if (gui_property (X_("midnam-custom-device-mode")).empty()) {
261 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
263 set_gui_property (X_("midnam-custom-device-mode"),
264 *device_names->custom_device_mode_names().begin());
268 ArdourWidgets::set_tooltip (_midnam_model_selector, _("External MIDI Device"));
269 ArdourWidgets::set_tooltip (_midnam_custom_device_mode_selector, _("External Device Mode"));
271 _midi_controls_box.pack_start (_midnam_model_selector, false, false, 2);
272 _midi_controls_box.pack_start (_midnam_custom_device_mode_selector, false, false, 2);
274 _midi_controls_box.set_homogeneous(false);
275 _midi_controls_box.set_border_width (2);
277 MIDI::Name::MidiPatchManager::instance().PatchesChanged.connect (*this, invalidator (*this),
278 boost::bind (&MidiTimeAxisView::setup_midnam_patches, this),
281 setup_midnam_patches ();
282 update_patch_selector ();
284 model_changed (gui_property(X_("midnam-model-name")));
285 custom_device_mode_changed (gui_property(X_("midnam-custom-device-mode")));
287 controls_vbox.pack_start(_midi_controls_box, false, false);
289 const string color_mode = gui_property ("color-mode");
290 if (!color_mode.empty()) {
291 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
292 if (_channel_selector && _color_mode == ChannelColors) {
293 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
297 set_color_mode (_color_mode, true, false);
299 const string note_mode = gui_property ("note-mode");
300 if (!note_mode.empty()) {
301 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
302 if (_percussion_mode_item) {
303 _percussion_mode_item->set_active (_note_mode == Percussive);
307 /* Look for any GUI object state nodes that represent automation children
308 * that should exist, and create the children.
311 const list<string> gui_ids = gui_object_state().all_ids ();
312 for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
315 Evoral::Parameter parameter (0, 0, 0);
317 bool const p = AutomationTimeAxisView::parse_state_id (
318 *i, route_id, has_parameter, parameter);
319 if (p && route_id == _route->id () && has_parameter) {
320 const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
321 create_automation_child (parameter, string_to<bool> (visible));
327 MidiTimeAxisView::processors_changed (RouteProcessorChange c)
329 RouteTimeAxisView::processors_changed (c);
330 update_patch_selector ();
334 MidiTimeAxisView::first_idle ()
341 MidiTimeAxisView::~MidiTimeAxisView ()
343 delete _channel_selector;
345 delete _piano_roll_header;
346 _piano_roll_header = 0;
348 delete _range_scroomer;
351 delete controller_menu;
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::update_patch_selector ()
397 typedef MIDI::Name::MidiPatchManager PatchManager;
398 PatchManager& patch_manager = PatchManager::instance();
400 bool pluginprovided = false;
402 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
403 if (pi && pi->plugin ()->has_midnam ()) {
404 pluginprovided = true;
405 std::string model_name = pi->plugin ()->midnam_model ();
406 if (gui_property (X_("midnam-model-name")) != model_name) {
407 model_changed (model_name);
412 if (patch_manager.all_models().empty() || pluginprovided) {
413 _midnam_model_selector.hide ();
414 _midnam_custom_device_mode_selector.hide ();
416 _midnam_model_selector.show ();
417 _midnam_custom_device_mode_selector.show ();
423 MidiTimeAxisView::model_changed(const std::string& model)
425 set_gui_property (X_("midnam-model-name"), model);
427 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
428 .custom_device_mode_names_by_model(model);
430 _midnam_model_selector.set_text(model);
431 _midnam_custom_device_mode_selector.clear_items();
433 for (std::list<std::string>::const_iterator i = device_modes.begin();
434 i != device_modes.end(); ++i) {
435 _midnam_custom_device_mode_selector.AddMenuElem(
436 Gtk::Menu_Helpers::MenuElem(
437 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
441 if (!device_modes.empty()) {
442 custom_device_mode_changed(device_modes.front());
445 if (device_modes.size() > 1) {
446 _midnam_custom_device_mode_selector.show();
448 _midnam_custom_device_mode_selector.hide();
451 // now this is a real bad hack
452 if (device_modes.size() > 0) {
453 _route->instrument_info().set_external_instrument (model, device_modes.front());
455 _route->instrument_info().set_external_instrument (model, "");
458 // Rebuild controller menu
459 _controller_menu_map.clear ();
460 delete controller_menu;
462 build_automation_action_menu(false);
464 if (patch_change_dialog ()) {
465 patch_change_dialog ()->refresh ();
470 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
472 const std::string model = gui_property (X_("midnam-model-name"));
474 set_gui_property (X_("midnam-custom-device-mode"), mode);
475 _midnam_custom_device_mode_selector.set_text(mode);
476 _route->instrument_info().set_external_instrument (model, mode);
480 MidiTimeAxisView::midi_view()
482 return dynamic_cast<MidiStreamView*>(_view);
486 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
488 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
489 _midi_controls_box.show ();
491 _midi_controls_box.hide();
494 if (h >= KEYBOARD_MIN_HEIGHT) {
495 if (is_track() && _range_scroomer) {
496 _range_scroomer->show();
498 if (is_track() && _piano_roll_header) {
499 _piano_roll_header->show();
502 if (is_track() && _range_scroomer) {
503 _range_scroomer->hide();
505 if (is_track() && _piano_roll_header) {
506 _piano_roll_header->hide();
510 /* We need to do this after changing visibility of our stuff, as it will
511 eventually trigger a call to Editor::reset_controls_layout_width(),
512 which needs to know if we have just shown or hidden a scroomer /
515 RouteTimeAxisView::set_height (h, m);
519 MidiTimeAxisView::append_extra_display_menu_items ()
521 using namespace Menu_Helpers;
523 MenuList& items = display_menu->items();
526 Menu *range_menu = manage(new Menu);
527 MenuList& range_items = range_menu->items();
528 range_menu->set_name ("ArdourContextMenu");
530 range_items.push_back (
531 MenuElem (_("Show Full Range"),
532 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
533 MidiStreamView::FullRange, true)));
535 range_items.push_back (
536 MenuElem (_("Fit Contents"),
537 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
538 MidiStreamView::ContentsRange, true)));
540 items.push_back (MenuElem (_("Note Range"), *range_menu));
541 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
542 items.push_back (MenuElem (_("Channel Selector..."),
543 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
545 items.push_back (MenuElem (_("Patch Selector..."),
546 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
548 items.push_back (MenuElem (_("Color Mode"), *build_color_mode_menu ()));
550 items.push_back (SeparatorElem ());
554 MidiTimeAxisView::toggle_channel_selector ()
556 if (!_channel_selector) {
557 _channel_selector = new MidiChannelSelectorWindow (midi_track());
559 if (_color_mode == ChannelColors) {
560 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
562 _channel_selector->set_default_channel_color ();
565 _channel_selector->show_all ();
567 _channel_selector->cycle_visibility ();
572 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
574 using namespace Menu_Helpers;
576 /* If we have a controller menu, we need to detach it before
577 RouteTimeAxis::build_automation_action_menu destroys the
578 menu it is attached to. Otherwise GTK destroys
579 controller_menu's gobj, meaning that it can't be reattached
580 below. See bug #3134.
583 if (controller_menu) {
584 detach_menu (*controller_menu);
587 _channel_command_menu_map.clear ();
588 RouteTimeAxisView::build_automation_action_menu (for_selection);
590 MenuList& automation_items = automation_action_menu->items();
592 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
594 if (selected_channels != 0) {
596 automation_items.push_back (SeparatorElem());
598 /* these 2 MIDI "command" types are semantically more like automation
599 than note data, but they are not MIDI controllers. We give them
600 special status in this menu, since they will not show up in the
601 controller list and anyone who actually knows something about MIDI
602 (!) would not expect to find them there.
605 add_channel_command_menu_item (
606 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
607 automation_items.back().set_sensitive (
608 !for_selection || _editor.get_selection().tracks.size() == 1);
609 add_channel_command_menu_item (
610 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
611 automation_items.back().set_sensitive (
612 !for_selection || _editor.get_selection().tracks.size() == 1);
614 /* now all MIDI controllers. Always offer the possibility that we will
615 rebuild the controllers menu since it might need to be updated after
616 a channel mode change or other change. Also detach it first in case
617 it has been used anywhere else.
620 build_controller_menu ();
622 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
624 if (!poly_pressure_menu) {
625 poly_pressure_menu = new Gtk::Menu;
628 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
630 automation_items.back().set_sensitive (
631 !for_selection || _editor.get_selection().tracks.size() == 1);
633 automation_items.push_back (
634 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
635 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
640 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
642 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
644 for (uint8_t chn = 0; chn < 16; chn++) {
645 if (selected_channels & (0x0001 << chn)) {
647 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
648 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
651 menu->set_active (yn);
658 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
660 AutomationType auto_type,
663 using namespace Menu_Helpers;
665 /* count the number of selected channels because we will build a different menu
666 structure if there is more than 1 selected.
669 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
672 for (uint8_t chn = 0; chn < 16; chn++) {
673 if (selected_channels & (0x0001 << chn)) {
682 /* multiple channels - create a submenu, with 1 item per channel */
684 Menu* chn_menu = manage (new Menu);
685 MenuList& chn_items (chn_menu->items());
686 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
688 /* add a couple of items to hide/show all of them */
690 chn_items.push_back (
691 MenuElem (_("Hide all channels"),
692 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
693 false, param_without_channel)));
694 chn_items.push_back (
695 MenuElem (_("Show all channels"),
696 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
697 true, param_without_channel)));
699 for (uint8_t chn = 0; chn < 16; chn++) {
700 if (selected_channels & (0x0001 << chn)) {
702 /* for each selected channel, add a menu item for this controller */
704 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
705 chn_items.push_back (
706 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
707 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
708 fully_qualified_param)));
710 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
711 bool visible = false;
714 if (track->marked_for_display()) {
719 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
720 _channel_command_menu_map[fully_qualified_param] = cmi;
721 cmi->set_active (visible);
725 /* now create an item in the parent menu that has the per-channel list as a submenu */
727 items.push_back (MenuElem (label, *chn_menu));
731 /* just one channel - create a single menu item for this command+channel combination*/
733 for (uint8_t chn = 0; chn < 16; chn++) {
734 if (selected_channels & (0x0001 << chn)) {
736 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
738 CheckMenuElem (label,
739 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
740 fully_qualified_param)));
742 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
743 bool visible = false;
746 if (track->marked_for_display()) {
751 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
752 _channel_command_menu_map[fully_qualified_param] = cmi;
753 cmi->set_active (visible);
755 /* one channel only */
762 /** Add a single menu item for a controller on one channel. */
764 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
766 const std::string& name)
768 using namespace Menu_Helpers;
770 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
771 for (uint8_t chn = 0; chn < 16; chn++) {
772 if (selected_channels & (0x0001 << chn)) {
774 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
775 ctl_items.push_back (
777 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
779 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
780 fully_qualified_param)));
781 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
783 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
784 fully_qualified_param);
786 bool visible = false;
788 if (track->marked_for_display()) {
793 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
794 _controller_menu_map[fully_qualified_param] = cmi;
795 cmi->set_active (visible);
797 /* one channel only */
803 /** Add a submenu with 1 item per channel for a controller on many channels. */
805 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
807 const std::string& name)
809 using namespace Menu_Helpers;
811 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
813 Menu* chn_menu = manage (new Menu);
814 MenuList& chn_items (chn_menu->items());
816 /* add a couple of items to hide/show this controller on all channels */
818 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
819 chn_items.push_back (
820 MenuElem (_("Hide all channels"),
821 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
822 false, param_without_channel)));
823 chn_items.push_back (
824 MenuElem (_("Show all channels"),
825 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
826 true, param_without_channel)));
828 for (uint8_t chn = 0; chn < 16; chn++) {
829 if (selected_channels & (0x0001 << chn)) {
831 /* for each selected channel, add a menu item for this controller */
833 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
834 chn_items.push_back (
835 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
836 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
837 fully_qualified_param)));
839 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
840 fully_qualified_param);
841 bool visible = false;
844 if (track->marked_for_display()) {
849 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
850 _controller_menu_map[fully_qualified_param] = cmi;
851 cmi->set_active (visible);
855 /* add the per-channel menu to the list of controllers, with the name of the controller */
856 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
858 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
861 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
862 MidiTimeAxisView::get_device_mode()
864 using namespace MIDI::Name;
866 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
868 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
871 return device_names->custom_device_mode_by_name(
872 gui_property (X_("midnam-custom-device-mode")));
875 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
876 MidiTimeAxisView::get_device_names()
878 using namespace MIDI::Name;
880 const std::string model = gui_property (X_("midnam-model-name"));
882 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
883 .document_by_model(model);
885 return midnam->master_device_names(model);
887 return boost::shared_ptr<MasterDeviceNames>();
892 MidiTimeAxisView::build_controller_menu ()
894 using namespace Menu_Helpers;
896 if (controller_menu) {
897 /* it exists and has not been invalidated by a channel mode change */
901 controller_menu = new Menu; // explicitly managed by us
902 MenuList& items (controller_menu->items());
904 /* create several "top level" menu items for sets of controllers (16 at a
905 time), and populate each one with a submenu for each controller+channel
906 combination covering the currently selected channels for this track
909 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
911 /* count the number of selected channels because we will build a different menu
912 structure if there is more than 1 selected.
916 for (uint8_t chn = 0; chn < 16; chn++) {
917 if (selected_channels & (0x0001 << chn)) {
924 using namespace MIDI::Name;
925 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
927 if (device_names && !device_names->controls().empty()) {
928 /* Controllers names available in midnam file, generate fancy menu */
929 unsigned n_items = 0;
930 unsigned n_groups = 0;
932 /* keep track of CC numbers that are added */
933 uint16_t ctl_start = 1;
934 uint16_t ctl_end = 1;
936 MasterDeviceNames::ControlNameLists const& ctllist (device_names->controls());
938 size_t total_ctrls = 0;
939 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
940 boost::shared_ptr<ControlNameList> name_list = l->second;
941 total_ctrls += name_list->controls().size();
944 bool to_top_level = total_ctrls < 32;
946 /* TODO: This is not correct, should look up the currently applicable ControlNameList
947 and only build a menu for that one. */
948 for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
949 boost::shared_ptr<ControlNameList> name_list = l->second;
950 Menu* ctl_menu = NULL;
952 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
953 c != name_list->controls().end();) {
954 const uint16_t ctl = c->second->number();
956 /* Skip bank select controllers since they're handled specially */
957 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
960 ctl_menu = controller_menu;
961 } else if (!ctl_menu) {
962 /* Create a new submenu */
963 ctl_menu = manage (new Menu);
967 MenuList& ctl_items (ctl_menu->items());
969 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
971 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
978 if (!ctl_menu || to_top_level) {
982 if (++n_items == 32 || ctl < ctl_start || c == name_list->controls().end()) {
983 /* Submenu has 32 items or we're done, or a new name-list started:
984 * add it to controller menu and reset */
985 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), ctl_start, ctl_end), *ctl_menu));
993 /* No controllers names, generate generic numeric menu */
994 for (int i = 0; i < 127; i += 32) {
995 Menu* ctl_menu = manage (new Menu);
996 MenuList& ctl_items (ctl_menu->items());
998 for (int ctl = i; ctl < i + 32; ++ctl) {
999 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1000 /* Skip bank select controllers since they're handled specially */
1005 add_multi_channel_controller_item(
1006 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1008 add_single_channel_controller_item(
1009 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1013 /* Add submenu for this block of controllers to controller menu */
1017 /* skip 0x00 and 0x20 (bank-select) */
1018 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i + 1, i + 31), *ctl_menu));
1021 items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i + 31), *ctl_menu));
1029 MidiTimeAxisView::build_note_mode_menu()
1031 using namespace Menu_Helpers;
1033 Menu* mode_menu = manage (new Menu);
1034 MenuList& items = mode_menu->items();
1035 mode_menu->set_name ("ArdourContextMenu");
1037 RadioMenuItem::Group mode_group;
1039 RadioMenuElem (mode_group,_("Sustained"),
1040 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1042 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1043 _note_mode_item->set_active(_note_mode == Sustained);
1046 RadioMenuElem (mode_group, _("Percussive"),
1047 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1048 Percussive, true)));
1049 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1050 _percussion_mode_item->set_active(_note_mode == Percussive);
1056 MidiTimeAxisView::build_color_mode_menu()
1058 using namespace Menu_Helpers;
1060 Menu* mode_menu = manage (new Menu);
1061 MenuList& items = mode_menu->items();
1062 mode_menu->set_name ("ArdourContextMenu");
1064 RadioMenuItem::Group mode_group;
1066 RadioMenuElem (mode_group, _("Meter Colors"),
1067 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1068 MeterColors, false, true, true)));
1069 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1070 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1073 RadioMenuElem (mode_group, _("Channel Colors"),
1074 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1075 ChannelColors, false, true, true)));
1076 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1077 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1080 RadioMenuElem (mode_group, _("Track Color"),
1081 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1082 TrackColor, false, true, true)));
1083 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1084 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1090 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1092 if (apply_to_selection) {
1093 _editor.get_selection().tracks.foreach_midi_time_axis (
1094 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1096 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1098 midi_track()->set_note_mode(mode);
1099 set_gui_property ("note-mode", enum_2_string(_note_mode));
1100 _view->redisplay_track();
1106 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1108 if (apply_to_selection) {
1109 _editor.get_selection().tracks.foreach_midi_time_axis (
1110 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1112 if (_color_mode == mode && !force) {
1116 if (_channel_selector) {
1117 if (mode == ChannelColors) {
1118 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1120 _channel_selector->set_default_channel_color();
1125 set_gui_property ("color-mode", enum_2_string(_color_mode));
1127 _view->redisplay_track();
1133 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1135 if (apply_to_selection) {
1136 _editor.get_selection().tracks.foreach_midi_time_axis (
1137 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1139 if (!_ignore_signals) {
1140 midi_view()->set_note_range(range);
1146 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1148 using namespace MIDI::Name;
1150 if (apply_to_selection) {
1151 _editor.get_selection().tracks.foreach_midi_time_axis (
1152 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1155 // Show existing automation
1156 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1158 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1159 create_automation_child(*i, true);
1162 // Show automation for all controllers named in midnam file
1163 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1164 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1165 device_names && !device_names->controls().empty()) {
1166 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1167 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1168 for (uint32_t chn = 0; chn < 16; ++chn) {
1169 if ((selected_channels & (0x0001 << chn)) == 0) {
1170 // Channel not in use
1174 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1180 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1181 chan_names->control_list_name());
1182 if (!control_names) {
1186 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1187 c != control_names->controls().end();
1189 const uint16_t ctl = c->second->number();
1190 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1191 /* Skip bank select controllers since they're handled specially */
1192 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1193 create_automation_child(param, true);
1200 RouteTimeAxisView::show_all_automation ();
1205 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1207 if (apply_to_selection) {
1208 _editor.get_selection().tracks.foreach_midi_time_axis (
1209 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1212 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1214 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1215 create_automation_child (*i, true);
1219 RouteTimeAxisView::show_existing_automation ();
1223 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1226 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1228 if (param.type() == NullAutomation) {
1232 AutomationTracks::iterator existing = _automation_tracks.find (param);
1234 if (existing != _automation_tracks.end()) {
1236 /* automation track created because we had existing data for
1237 * the processor, but visibility may need to be controlled
1238 * since it will have been set visible by default.
1241 existing->second->set_marked_for_display (show);
1250 boost::shared_ptr<AutomationTimeAxisView> track;
1251 boost::shared_ptr<AutomationControl> control;
1254 switch (param.type()) {
1256 case GainAutomation:
1257 create_gain_automation_child (param, show);
1260 case MuteAutomation:
1261 create_mute_automation_child (param, show);
1264 case PluginAutomation:
1265 /* handled elsewhere */
1268 case MidiCCAutomation:
1269 case MidiPgmChangeAutomation:
1270 case MidiPitchBenderAutomation:
1271 case MidiChannelPressureAutomation:
1272 case MidiSystemExclusiveAutomation:
1273 /* These controllers are region "automation" - they are owned
1274 * by regions (and their MidiModels), not by the track. As a
1275 * result there is no AutomationList/Line for the track, but we create
1276 * a controller for the user to write immediate events, so the editor
1277 * can act as a control surface for the present MIDI controllers.
1279 * TODO: Record manipulation of the controller to regions?
1282 control = _route->automation_control(param, true);
1283 track.reset (new AutomationTimeAxisView (
1286 control ? _route : boost::shared_ptr<Automatable> (),
1293 _route->describe_parameter(param)));
1296 _view->foreach_regionview (
1297 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1300 add_automation_child (param, track, show);
1302 reshow_selection (_editor.get_selection().time);
1307 case PanWidthAutomation:
1308 case PanElevationAutomation:
1309 case PanAzimuthAutomation:
1310 ensure_pan_views (show);
1314 error << "MidiTimeAxisView: unknown automation child "
1315 << EventTypeMap::instance().to_symbol(param) << endmsg;
1320 MidiTimeAxisView::route_active_changed ()
1322 RouteUI::route_active_changed ();
1323 update_control_names();
1327 MidiTimeAxisView::update_control_names ()
1330 if (_route->active()) {
1331 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1332 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1334 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1335 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1337 } else { // MIDI bus (which doesn't exist yet..)
1338 if (_route->active()) {
1339 controls_base_selected_name = "BusControlsBaseSelected";
1340 controls_base_unselected_name = "BusControlsBaseUnselected";
1342 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1343 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1348 controls_ebox.set_name (controls_base_selected_name);
1349 time_axis_frame.set_name (controls_base_selected_name);
1351 controls_ebox.set_name (controls_base_unselected_name);
1352 time_axis_frame.set_name (controls_base_unselected_name);
1357 MidiTimeAxisView::set_note_selection (uint8_t note)
1359 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1361 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1363 /* set_note_selection_region_view() will not work with multiple regions,
1364 * as each individual `foreach` call will clear prior selection.
1365 * Use clear_midi_notes() and add_note_selection_region_view() instead. */
1367 _editor.get_selection().clear_midi_notes();
1369 if (_view->num_selected_regionviews() == 0) {
1370 _view->foreach_regionview (
1371 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1374 _view->foreach_selected_regionview (
1375 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1379 _editor.commit_reversible_selection_op();
1383 MidiTimeAxisView::add_note_selection (uint8_t note)
1385 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1387 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1389 if (_view->num_selected_regionviews() == 0) {
1390 _view->foreach_regionview (
1391 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1394 _view->foreach_selected_regionview (
1395 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1399 _editor.commit_reversible_selection_op();
1403 MidiTimeAxisView::extend_note_selection (uint8_t note)
1405 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1407 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1409 if (_view->num_selected_regionviews() == 0) {
1410 _view->foreach_regionview (
1411 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1414 _view->foreach_selected_regionview (
1415 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1419 _editor.commit_reversible_selection_op();
1423 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1425 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1427 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1429 if (_view->num_selected_regionviews() == 0) {
1430 _view->foreach_regionview (
1431 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1434 _view->foreach_selected_regionview (
1435 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1439 _editor.commit_reversible_selection_op();
1443 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > >& selection)
1445 _view->foreach_regionview (
1446 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1450 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1452 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1456 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1458 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1462 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1464 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1468 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1470 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1474 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection)
1476 Evoral::Sequence<Temporal::Beats>::Notes selected;
1477 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1479 std::set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > notes;
1481 Evoral::Sequence<Temporal::Beats>::Notes::iterator sel_it;
1482 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1483 notes.insert (*sel_it);
1486 if (!notes.empty()) {
1487 selection.push_back (make_pair ((rv)->region()->id(), notes));
1492 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1494 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1498 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1499 bool changed = false;
1503 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1505 for (uint32_t chn = 0; chn < 16; ++chn) {
1506 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1507 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1513 if ((selected_channels & (0x0001 << chn)) == 0) {
1514 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1515 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1517 changed = track->set_marked_for_display (false) || changed;
1519 changed = track->set_marked_for_display (true) || changed;
1526 /* TODO: Bender, Pressure */
1528 /* invalidate the controller menu, so that we rebuild it next time */
1529 _controller_menu_map.clear ();
1530 delete controller_menu;
1531 controller_menu = 0;
1539 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1541 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1546 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1547 if (i != _controller_menu_map.end()) {
1551 i = _channel_command_menu_map.find (param);
1552 if (i != _channel_command_menu_map.end()) {
1559 boost::shared_ptr<MidiRegion>
1560 MidiTimeAxisView::add_region (samplepos_t f, samplecnt_t length, bool commit)
1562 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1563 MusicSample pos (f, 0);
1566 real_editor->begin_reversible_command (Operations::create_region);
1568 playlist()->clear_changes ();
1570 real_editor->snap_to (pos, RoundNearest);
1572 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1575 plist.add (ARDOUR::Properties::start, 0);
1576 plist.add (ARDOUR::Properties::length, length);
1577 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1579 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1580 /* sets beat position */
1581 region->set_position (pos.sample, pos.division);
1582 playlist()->add_region (region, pos.sample, 1.0, false, pos.division);
1583 _session->add_command (new StatefulDiffCommand (playlist()));
1586 real_editor->commit_reversible_command ();
1589 return boost::dynamic_pointer_cast<MidiRegion>(region);
1593 MidiTimeAxisView::ensure_step_editor ()
1595 if (!_step_editor) {
1596 _step_editor = new StepEditor (_editor, midi_track(), *this);
1601 MidiTimeAxisView::start_step_editing ()
1603 ensure_step_editor ();
1604 _step_editor->start_step_editing ();
1608 MidiTimeAxisView::stop_step_editing ()
1611 _step_editor->stop_step_editing ();
1615 /** @return channel (counted from 0) to add an event to, based on the current setting
1616 * of the channel selector.
1619 MidiTimeAxisView::get_channel_for_add () const
1621 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1623 uint8_t channel = 0;
1625 /* pick the highest selected channel, unless all channels are selected,
1626 which is interpreted to mean channel 1 (zero)
1629 for (uint16_t i = 0; i < 16; ++i) {
1630 if (chn_mask & (1<<i)) {
1636 if (chn_cnt == 16) {
1644 MidiTimeAxisView::note_range_changed ()
1646 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1647 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1651 MidiTimeAxisView::contents_height_changed ()
1653 _range_scroomer->queue_resize ();
1657 MidiTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1659 if (!_editor.internal_editing()) {
1660 // Non-internal paste, paste regions like any other route
1661 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1664 return midi_view()->paste(pos, selection, ctx, sub_num);