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 (&MidiTimeAxisView::reread_midnam, this),
432 pluginprovided = true;
433 std::string model_name = pi->plugin ()->midnam_model ();
434 if (gui_property (X_("midnam-model-name")) != model_name) {
435 model_changed (model_name);
440 if (patch_manager.all_models().empty() || pluginprovided) {
441 _midnam_model_selector.hide ();
442 _midnam_custom_device_mode_selector.hide ();
444 _midnam_model_selector.show ();
445 _midnam_custom_device_mode_selector.show ();
450 MidiTimeAxisView::reread_midnam ()
452 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
453 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(the_instrument);
454 bool rv = pi->plugin ()->read_midnam();
456 if (rv && _patch_change_dialog) {
457 _patch_change_dialog->refresh ();
461 MidiTimeAxisView::model_changed(const std::string& model)
463 set_gui_property (X_("midnam-model-name"), model);
465 const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
466 .custom_device_mode_names_by_model(model);
468 _midnam_model_selector.set_text(model);
469 _midnam_custom_device_mode_selector.clear_items();
471 for (std::list<std::string>::const_iterator i = device_modes.begin();
472 i != device_modes.end(); ++i) {
473 _midnam_custom_device_mode_selector.AddMenuElem(
474 Gtk::Menu_Helpers::MenuElem(
475 *i, sigc::bind(sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed),
479 if (!device_modes.empty()) {
480 custom_device_mode_changed(device_modes.front());
483 if (device_modes.size() > 1) {
484 _midnam_custom_device_mode_selector.show();
486 _midnam_custom_device_mode_selector.hide();
489 // now this is a real bad hack
490 if (device_modes.size() > 0) {
491 _route->instrument_info().set_external_instrument (model, device_modes.front());
493 _route->instrument_info().set_external_instrument (model, "");
496 // Rebuild controller menu
497 _controller_menu_map.clear ();
498 delete controller_menu;
500 build_automation_action_menu(false);
502 if (_patch_change_dialog) {
503 _patch_change_dialog->refresh ();
508 MidiTimeAxisView::custom_device_mode_changed(const std::string& mode)
510 const std::string model = gui_property (X_("midnam-model-name"));
512 set_gui_property (X_("midnam-custom-device-mode"), mode);
513 _midnam_custom_device_mode_selector.set_text(mode);
514 _route->instrument_info().set_external_instrument (model, mode);
518 MidiTimeAxisView::midi_view()
520 return dynamic_cast<MidiStreamView*>(_view);
524 MidiTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
526 if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
527 _midi_controls_box.show ();
529 _midi_controls_box.hide();
532 if (h >= KEYBOARD_MIN_HEIGHT) {
533 if (is_track() && _range_scroomer) {
534 _range_scroomer->show();
536 if (is_track() && _piano_roll_header) {
537 _piano_roll_header->show();
540 if (is_track() && _range_scroomer) {
541 _range_scroomer->hide();
543 if (is_track() && _piano_roll_header) {
544 _piano_roll_header->hide();
548 /* We need to do this after changing visibility of our stuff, as it will
549 eventually trigger a call to Editor::reset_controls_layout_width(),
550 which needs to know if we have just shown or hidden a scroomer /
553 RouteTimeAxisView::set_height (h, m);
557 MidiTimeAxisView::append_extra_display_menu_items ()
559 using namespace Menu_Helpers;
561 MenuList& items = display_menu->items();
564 Menu *range_menu = manage(new Menu);
565 MenuList& range_items = range_menu->items();
566 range_menu->set_name ("ArdourContextMenu");
568 range_items.push_back (
569 MenuElem (_("Show Full Range"),
570 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
571 MidiStreamView::FullRange, true)));
573 range_items.push_back (
574 MenuElem (_("Fit Contents"),
575 sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
576 MidiStreamView::ContentsRange, true)));
578 items.push_back (MenuElem (_("Note Range"), *range_menu));
579 items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
580 items.push_back (MenuElem (_("Channel Selector..."),
581 sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
583 items.push_back (MenuElem (_("Patch Selector..."),
584 sigc::mem_fun(*this, &MidiTimeAxisView::send_patch_change)));
586 color_mode_menu = build_color_mode_menu();
587 if (color_mode_menu) {
588 items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
591 items.push_back (SeparatorElem ());
595 MidiTimeAxisView::toggle_channel_selector ()
597 if (!_channel_selector) {
598 _channel_selector = new MidiChannelSelectorWindow (midi_track());
600 if (_color_mode == ChannelColors) {
601 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
603 _channel_selector->set_default_channel_color ();
606 _channel_selector->show_all ();
608 _channel_selector->cycle_visibility ();
613 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
615 using namespace Menu_Helpers;
617 /* If we have a controller menu, we need to detach it before
618 RouteTimeAxis::build_automation_action_menu destroys the
619 menu it is attached to. Otherwise GTK destroys
620 controller_menu's gobj, meaning that it can't be reattached
621 below. See bug #3134.
624 if (controller_menu) {
625 detach_menu (*controller_menu);
628 _channel_command_menu_map.clear ();
629 RouteTimeAxisView::build_automation_action_menu (for_selection);
631 MenuList& automation_items = automation_action_menu->items();
633 uint16_t selected_channels = midi_track()->get_playback_channel_mask();
635 if (selected_channels != 0) {
637 automation_items.push_back (SeparatorElem());
639 /* these 2 MIDI "command" types are semantically more like automation
640 than note data, but they are not MIDI controllers. We give them
641 special status in this menu, since they will not show up in the
642 controller list and anyone who actually knows something about MIDI
643 (!) would not expect to find them there.
646 add_channel_command_menu_item (
647 automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
648 automation_items.back().set_sensitive (
649 !for_selection || _editor.get_selection().tracks.size() == 1);
650 add_channel_command_menu_item (
651 automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
652 automation_items.back().set_sensitive (
653 !for_selection || _editor.get_selection().tracks.size() == 1);
655 /* now all MIDI controllers. Always offer the possibility that we will
656 rebuild the controllers menu since it might need to be updated after
657 a channel mode change or other change. Also detach it first in case
658 it has been used anywhere else.
661 build_controller_menu ();
663 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
665 if (!poly_pressure_menu) {
666 poly_pressure_menu = new Gtk::Menu;
669 automation_items.push_back (MenuElem (_("Polyphonic Pressure"), *poly_pressure_menu));
671 automation_items.back().set_sensitive (
672 !for_selection || _editor.get_selection().tracks.size() == 1);
674 automation_items.push_back (
675 MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
676 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
681 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
683 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
685 for (uint8_t chn = 0; chn < 16; chn++) {
686 if (selected_channels & (0x0001 << chn)) {
688 Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
689 Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
692 menu->set_active (yn);
699 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
701 AutomationType auto_type,
704 using namespace Menu_Helpers;
706 /* count the number of selected channels because we will build a different menu
707 structure if there is more than 1 selected.
710 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
713 for (uint8_t chn = 0; chn < 16; chn++) {
714 if (selected_channels & (0x0001 << chn)) {
723 /* multiple channels - create a submenu, with 1 item per channel */
725 Menu* chn_menu = manage (new Menu);
726 MenuList& chn_items (chn_menu->items());
727 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
729 /* add a couple of items to hide/show all of them */
731 chn_items.push_back (
732 MenuElem (_("Hide all channels"),
733 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
734 false, param_without_channel)));
735 chn_items.push_back (
736 MenuElem (_("Show all channels"),
737 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
738 true, param_without_channel)));
740 for (uint8_t chn = 0; chn < 16; chn++) {
741 if (selected_channels & (0x0001 << chn)) {
743 /* for each selected channel, add a menu item for this controller */
745 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
746 chn_items.push_back (
747 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
748 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
749 fully_qualified_param)));
751 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
752 bool visible = false;
755 if (track->marked_for_display()) {
760 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
761 _channel_command_menu_map[fully_qualified_param] = cmi;
762 cmi->set_active (visible);
766 /* now create an item in the parent menu that has the per-channel list as a submenu */
768 items.push_back (MenuElem (label, *chn_menu));
772 /* just one channel - create a single menu item for this command+channel combination*/
774 for (uint8_t chn = 0; chn < 16; chn++) {
775 if (selected_channels & (0x0001 << chn)) {
777 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
779 CheckMenuElem (label,
780 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
781 fully_qualified_param)));
783 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
784 bool visible = false;
787 if (track->marked_for_display()) {
792 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&items.back());
793 _channel_command_menu_map[fully_qualified_param] = cmi;
794 cmi->set_active (visible);
796 /* one channel only */
803 /** Add a single menu item for a controller on one channel. */
805 MidiTimeAxisView::add_single_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();
812 for (uint8_t chn = 0; chn < 16; chn++) {
813 if (selected_channels & (0x0001 << chn)) {
815 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
816 ctl_items.push_back (
818 string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn + 1)),
820 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
821 fully_qualified_param)));
822 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
824 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
825 fully_qualified_param);
827 bool visible = false;
829 if (track->marked_for_display()) {
834 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&ctl_items.back());
835 _controller_menu_map[fully_qualified_param] = cmi;
836 cmi->set_active (visible);
838 /* one channel only */
844 /** Add a submenu with 1 item per channel for a controller on many channels. */
846 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
848 const std::string& name)
850 using namespace Menu_Helpers;
852 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
854 Menu* chn_menu = manage (new Menu);
855 MenuList& chn_items (chn_menu->items());
857 /* add a couple of items to hide/show this controller on all channels */
859 Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
860 chn_items.push_back (
861 MenuElem (_("Hide all channels"),
862 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
863 false, param_without_channel)));
864 chn_items.push_back (
865 MenuElem (_("Show all channels"),
866 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
867 true, param_without_channel)));
869 for (uint8_t chn = 0; chn < 16; chn++) {
870 if (selected_channels & (0x0001 << chn)) {
872 /* for each selected channel, add a menu item for this controller */
874 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
875 chn_items.push_back (
876 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
877 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
878 fully_qualified_param)));
880 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
881 fully_qualified_param);
882 bool visible = false;
885 if (track->marked_for_display()) {
890 Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*>(&chn_items.back());
891 _controller_menu_map[fully_qualified_param] = cmi;
892 cmi->set_active (visible);
896 /* add the per-channel menu to the list of controllers, with the name of the controller */
897 ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
899 dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
902 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
903 MidiTimeAxisView::get_device_mode()
905 using namespace MIDI::Name;
907 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
909 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
912 return device_names->custom_device_mode_by_name(
913 gui_property (X_("midnam-custom-device-mode")));
916 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
917 MidiTimeAxisView::get_device_names()
919 using namespace MIDI::Name;
921 const std::string model = gui_property (X_("midnam-model-name"));
923 boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
924 .document_by_model(model);
926 return midnam->master_device_names(model);
928 return boost::shared_ptr<MasterDeviceNames>();
933 MidiTimeAxisView::build_controller_menu ()
935 using namespace Menu_Helpers;
937 if (controller_menu) {
938 /* it exists and has not been invalidated by a channel mode change */
942 controller_menu = new Menu; // explicitly managed by us
943 MenuList& items (controller_menu->items());
945 /* create several "top level" menu items for sets of controllers (16 at a
946 time), and populate each one with a submenu for each controller+channel
947 combination covering the currently selected channels for this track
950 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
952 /* count the number of selected channels because we will build a different menu
953 structure if there is more than 1 selected.
957 for (uint8_t chn = 0; chn < 16; chn++) {
958 if (selected_channels & (0x0001 << chn)) {
965 using namespace MIDI::Name;
966 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
968 if (device_names && !device_names->controls().empty()) {
969 /* Controllers names available in midnam file, generate fancy menu */
970 unsigned n_items = 0;
971 unsigned n_groups = 0;
973 /* TODO: This is not correct, should look up the currently applicable ControlNameList
974 and only build a menu for that one. */
975 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
976 l != device_names->controls().end(); ++l) {
977 boost::shared_ptr<ControlNameList> name_list = l->second;
978 Menu* ctl_menu = NULL;
980 for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
981 c != name_list->controls().end();) {
982 const uint16_t ctl = c->second->number();
983 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
984 /* Skip bank select controllers since they're handled specially */
986 /* Create a new submenu */
987 ctl_menu = manage (new Menu);
990 MenuList& ctl_items (ctl_menu->items());
992 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
994 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
999 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
1000 /* Submenu has 16 items or we're done, add it to controller menu and reset */
1002 MenuElem(string_compose(_("Controllers %1-%2"),
1003 (16 * n_groups), (16 * n_groups) + n_items - 1),
1012 /* No controllers names, generate generic numeric menu */
1013 for (int i = 0; i < 127; i += 16) {
1014 Menu* ctl_menu = manage (new Menu);
1015 MenuList& ctl_items (ctl_menu->items());
1017 for (int ctl = i; ctl < i+16; ++ctl) {
1018 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
1019 /* Skip bank select controllers since they're handled specially */
1024 add_multi_channel_controller_item(
1025 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1027 add_single_channel_controller_item(
1028 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
1032 /* Add submenu for this block of controllers to controller menu */
1034 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
1041 MidiTimeAxisView::build_note_mode_menu()
1043 using namespace Menu_Helpers;
1045 Menu* mode_menu = manage (new Menu);
1046 MenuList& items = mode_menu->items();
1047 mode_menu->set_name ("ArdourContextMenu");
1049 RadioMenuItem::Group mode_group;
1051 RadioMenuElem (mode_group,_("Sustained"),
1052 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1054 _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1055 _note_mode_item->set_active(_note_mode == Sustained);
1058 RadioMenuElem (mode_group, _("Percussive"),
1059 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
1060 Percussive, true)));
1061 _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1062 _percussion_mode_item->set_active(_note_mode == Percussive);
1068 MidiTimeAxisView::build_color_mode_menu()
1070 using namespace Menu_Helpers;
1072 Menu* mode_menu = manage (new Menu);
1073 MenuList& items = mode_menu->items();
1074 mode_menu->set_name ("ArdourContextMenu");
1076 RadioMenuItem::Group mode_group;
1078 RadioMenuElem (mode_group, _("Meter Colors"),
1079 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1080 MeterColors, false, true, true)));
1081 _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1082 _meter_color_mode_item->set_active(_color_mode == MeterColors);
1085 RadioMenuElem (mode_group, _("Channel Colors"),
1086 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1087 ChannelColors, false, true, true)));
1088 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1089 _channel_color_mode_item->set_active(_color_mode == ChannelColors);
1092 RadioMenuElem (mode_group, _("Track Color"),
1093 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
1094 TrackColor, false, true, true)));
1095 _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
1096 _channel_color_mode_item->set_active(_color_mode == TrackColor);
1102 MidiTimeAxisView::send_patch_change ()
1107 if (_patch_change_dialog) {
1108 _patch_change_dialog->present ();
1112 PatchChangeGridDialog* d = new PatchChangeGridDialog (_route);
1113 _patch_change_dialog = d;
1118 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
1120 if (apply_to_selection) {
1121 _editor.get_selection().tracks.foreach_midi_time_axis (
1122 boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
1124 if (_note_mode != mode || midi_track()->note_mode() != mode) {
1126 midi_track()->set_note_mode(mode);
1127 set_gui_property ("note-mode", enum_2_string(_note_mode));
1128 _view->redisplay_track();
1134 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
1136 if (apply_to_selection) {
1137 _editor.get_selection().tracks.foreach_midi_time_axis (
1138 boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
1140 if (_color_mode == mode && !force) {
1144 if (_channel_selector) {
1145 if (mode == ChannelColors) {
1146 _channel_selector->set_channel_colors(NoteBase::midi_channel_colors);
1148 _channel_selector->set_default_channel_color();
1153 set_gui_property ("color-mode", enum_2_string(_color_mode));
1155 _view->redisplay_track();
1161 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1163 if (apply_to_selection) {
1164 _editor.get_selection().tracks.foreach_midi_time_axis (
1165 boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1167 if (!_ignore_signals) {
1168 midi_view()->set_note_range(range);
1174 MidiTimeAxisView::update_range()
1179 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1181 using namespace MIDI::Name;
1183 if (apply_to_selection) {
1184 _editor.get_selection().tracks.foreach_midi_time_axis (
1185 boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1188 // Show existing automation
1189 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1191 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1192 create_automation_child(*i, true);
1195 // Show automation for all controllers named in midnam file
1196 boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
1197 if (gui_property (X_("midnam-model-name")) != "Generic" &&
1198 device_names && !device_names->controls().empty()) {
1199 const std::string device_mode = gui_property (X_("midnam-custom-device-mode"));
1200 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1201 for (uint32_t chn = 0; chn < 16; ++chn) {
1202 if ((selected_channels & (0x0001 << chn)) == 0) {
1203 // Channel not in use
1207 boost::shared_ptr<ChannelNameSet> chan_names = device_names->channel_name_set_by_channel(
1213 boost::shared_ptr<ControlNameList> control_names = device_names->control_name_list(
1214 chan_names->control_list_name());
1215 if (!control_names) {
1219 for (ControlNameList::Controls::const_iterator c = control_names->controls().begin();
1220 c != control_names->controls().end();
1222 const uint16_t ctl = c->second->number();
1223 if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
1224 /* Skip bank select controllers since they're handled specially */
1225 const Evoral::Parameter param(MidiCCAutomation, chn, ctl);
1226 create_automation_child(param, true);
1233 RouteTimeAxisView::show_all_automation ();
1238 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1240 if (apply_to_selection) {
1241 _editor.get_selection().tracks.foreach_midi_time_axis (
1242 boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1245 const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1247 for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1248 create_automation_child (*i, true);
1252 RouteTimeAxisView::show_existing_automation ();
1256 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1259 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1261 if (param.type() == NullAutomation) {
1265 AutomationTracks::iterator existing = _automation_tracks.find (param);
1267 if (existing != _automation_tracks.end()) {
1269 /* automation track created because we had existing data for
1270 * the processor, but visibility may need to be controlled
1271 * since it will have been set visible by default.
1274 existing->second->set_marked_for_display (show);
1283 boost::shared_ptr<AutomationTimeAxisView> track;
1284 boost::shared_ptr<AutomationControl> control;
1287 switch (param.type()) {
1289 case GainAutomation:
1290 create_gain_automation_child (param, show);
1293 case MuteAutomation:
1294 create_mute_automation_child (param, show);
1297 case PluginAutomation:
1298 /* handled elsewhere */
1301 case MidiCCAutomation:
1302 case MidiPgmChangeAutomation:
1303 case MidiPitchBenderAutomation:
1304 case MidiChannelPressureAutomation:
1305 case MidiSystemExclusiveAutomation:
1306 /* These controllers are region "automation" - they are owned
1307 * by regions (and their MidiModels), not by the track. As a
1308 * result there is no AutomationList/Line for the track, but we create
1309 * a controller for the user to write immediate events, so the editor
1310 * can act as a control surface for the present MIDI controllers.
1312 * TODO: Record manipulation of the controller to regions?
1315 control = _route->automation_control(param, true);
1316 track.reset (new AutomationTimeAxisView (
1319 control ? _route : boost::shared_ptr<Automatable> (),
1326 _route->describe_parameter(param)));
1329 _view->foreach_regionview (
1330 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1333 add_automation_child (param, track, show);
1335 reshow_selection (_editor.get_selection().time);
1340 case PanWidthAutomation:
1341 case PanElevationAutomation:
1342 case PanAzimuthAutomation:
1343 ensure_pan_views (show);
1347 error << "MidiTimeAxisView: unknown automation child "
1348 << EventTypeMap::instance().to_symbol(param) << endmsg;
1353 MidiTimeAxisView::route_active_changed ()
1355 RouteUI::route_active_changed ();
1356 update_control_names();
1360 MidiTimeAxisView::update_control_names ()
1363 if (_route->active()) {
1364 controls_base_selected_name = "MidiTrackControlsBaseSelected";
1365 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1367 controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1368 controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1370 } else { // MIDI bus (which doesn't exist yet..)
1371 if (_route->active()) {
1372 controls_base_selected_name = "BusControlsBaseSelected";
1373 controls_base_unselected_name = "BusControlsBaseUnselected";
1375 controls_base_selected_name = "BusControlsBaseInactiveSelected";
1376 controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1381 controls_ebox.set_name (controls_base_selected_name);
1382 time_axis_frame.set_name (controls_base_selected_name);
1384 controls_ebox.set_name (controls_base_unselected_name);
1385 time_axis_frame.set_name (controls_base_unselected_name);
1390 MidiTimeAxisView::set_note_selection (uint8_t note)
1392 uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1394 _editor.begin_reversible_selection_op (X_("Set Note Selection"));
1396 if (_view->num_selected_regionviews() == 0) {
1397 _view->foreach_regionview (
1398 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1401 _view->foreach_selected_regionview (
1402 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1406 _editor.commit_reversible_selection_op();
1410 MidiTimeAxisView::add_note_selection (uint8_t note)
1412 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1414 _editor.begin_reversible_selection_op (X_("Add Note Selection"));
1416 if (_view->num_selected_regionviews() == 0) {
1417 _view->foreach_regionview (
1418 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1421 _view->foreach_selected_regionview (
1422 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1426 _editor.commit_reversible_selection_op();
1430 MidiTimeAxisView::extend_note_selection (uint8_t note)
1432 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1434 _editor.begin_reversible_selection_op (X_("Extend Note Selection"));
1436 if (_view->num_selected_regionviews() == 0) {
1437 _view->foreach_regionview (
1438 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1441 _view->foreach_selected_regionview (
1442 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1446 _editor.commit_reversible_selection_op();
1450 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1452 const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
1454 _editor.begin_reversible_selection_op (X_("Toggle Note Selection"));
1456 if (_view->num_selected_regionviews() == 0) {
1457 _view->foreach_regionview (
1458 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1461 _view->foreach_selected_regionview (
1462 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1466 _editor.commit_reversible_selection_op();
1470 MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
1472 _view->foreach_regionview (
1473 sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
1477 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1479 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1483 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1485 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1489 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1491 dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1495 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1497 dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1501 MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
1503 Evoral::Sequence<Evoral::Beats>::Notes selected;
1504 dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
1506 std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
1508 Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
1509 for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
1510 notes.insert (*sel_it);
1513 if (!notes.empty()) {
1514 selection.push_back (make_pair ((rv)->region()->id(), notes));
1519 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1521 /* hide all automation tracks that use the wrong channel(s) and show all those that use
1525 const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
1526 bool changed = false;
1530 for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1532 for (uint32_t chn = 0; chn < 16; ++chn) {
1533 Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1534 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1540 if ((selected_channels & (0x0001 << chn)) == 0) {
1541 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1542 which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1544 changed = track->set_marked_for_display (false) || changed;
1546 changed = track->set_marked_for_display (true) || changed;
1553 /* TODO: Bender, Pressure */
1555 /* invalidate the controller menu, so that we rebuild it next time */
1556 _controller_menu_map.clear ();
1557 delete controller_menu;
1558 controller_menu = 0;
1566 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1568 Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1573 ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1574 if (i != _controller_menu_map.end()) {
1578 i = _channel_command_menu_map.find (param);
1579 if (i != _channel_command_menu_map.end()) {
1586 boost::shared_ptr<MidiRegion>
1587 MidiTimeAxisView::add_region (framepos_t f, framecnt_t length, bool commit)
1589 Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1590 MusicFrame pos (f, 0);
1593 real_editor->begin_reversible_command (Operations::create_region);
1595 playlist()->clear_changes ();
1597 real_editor->snap_to (pos, RoundNearest);
1599 boost::shared_ptr<Source> src = _session->create_midi_source_by_stealing_name (view()->trackview().track());
1602 plist.add (ARDOUR::Properties::start, 0);
1603 plist.add (ARDOUR::Properties::length, length);
1604 plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1606 boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1607 /* sets beat position */
1608 region->set_position (pos.frame, pos.division);
1609 playlist()->add_region (region, pos.frame, 1.0, false, pos.division);
1610 _session->add_command (new StatefulDiffCommand (playlist()));
1613 real_editor->commit_reversible_command ();
1616 return boost::dynamic_pointer_cast<MidiRegion>(region);
1620 MidiTimeAxisView::ensure_step_editor ()
1622 if (!_step_editor) {
1623 _step_editor = new StepEditor (_editor, midi_track(), *this);
1628 MidiTimeAxisView::start_step_editing ()
1630 ensure_step_editor ();
1631 _step_editor->start_step_editing ();
1635 MidiTimeAxisView::stop_step_editing ()
1638 _step_editor->stop_step_editing ();
1642 /** @return channel (counted from 0) to add an event to, based on the current setting
1643 * of the channel selector.
1646 MidiTimeAxisView::get_channel_for_add () const
1648 uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
1650 uint8_t channel = 0;
1652 /* pick the highest selected channel, unless all channels are selected,
1653 which is interpreted to mean channel 1 (zero)
1656 for (uint16_t i = 0; i < 16; ++i) {
1657 if (chn_mask & (1<<i)) {
1663 if (chn_cnt == 16) {
1671 MidiTimeAxisView::note_range_changed ()
1673 set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1674 set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1678 MidiTimeAxisView::contents_height_changed ()
1680 _range_scroomer->queue_resize ();
1684 MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1686 if (!_editor.internal_editing()) {
1687 // Non-internal paste, paste regions like any other route
1688 return RouteTimeAxisView::paste(pos, selection, ctx, sub_num);
1691 return midi_view()->paste(pos, selection, ctx, sub_num);